Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new Crypto Wallet Exploit Challenge #2064

Merged
5 changes: 5 additions & 0 deletions config.schema.yml
Expand Up @@ -509,6 +509,11 @@ ctf:
type: string
code:
type: string
web3WalletChallenge:
name:
type: string
code:
type: string
securityPolicyChallenge:
name:
type: string
Expand Down
5 changes: 4 additions & 1 deletion config/fbctf.yml
Expand Up @@ -326,4 +326,7 @@ ctf:
code: AF
nftMintChallenge:
name: United Arab Emirates
code: UAE
code: UAE
web3WalletChallenge:
name: Mexico
code: MEX
11 changes: 11 additions & 0 deletions data/static/challenges.yml
Expand Up @@ -106,6 +106,17 @@
hintUrl: ''
mitigationUrl: ~
key: nftMintChallenge
-
name: 'Wallet Depletion'
category: 'Miscellaneous'
tags:
- Web3
description: 'Try and withdraw more ETH than you deposited in the new wallet.'
difficulty: 6
hint: 'Try to exploit the contract of the wallet.'
hintUrl: ''
mitigationUrl: ~
key: web3WalletChallenge
-
name: 'Blocked RCE DoS'
category: 'Insecure Deserialization'
Expand Down
4 changes: 4 additions & 0 deletions data/static/codefixes/adminSectionChallenge_1_correct.ts
Expand Up @@ -162,6 +162,10 @@ const routes: Routes = [
path: 'juicy-nft',
component: NFTUnlockComponent
},
{
path: 'wallet-web3',
loadChildren: async () => await loadWeb3WalletModule()
},
{
path: 'bee-haven',
loadChildren: async () => await loadFaucetModule()
Expand Down
4 changes: 4 additions & 0 deletions data/static/codefixes/adminSectionChallenge_2.ts
Expand Up @@ -159,6 +159,10 @@ const routes: Routes = [
path: 'juicy-nft',
component: NFTUnlockComponent
},
{
path: 'wallet-web3',
loadChildren: async () => await loadWeb3WalletModule()
},
{
path: 'bee-haven',
loadChildren: async () => await loadFaucetModule()
Expand Down
4 changes: 4 additions & 0 deletions data/static/codefixes/adminSectionChallenge_3.ts
Expand Up @@ -159,6 +159,10 @@ const routes: Routes = [
path: 'juicy-nft',
component: NFTUnlockComponent
},
{
path: 'wallet-web3',
loadChildren: async () => await loadWeb3WalletModule()
},
{
path: 'bee-haven',
loadChildren: async () => await loadFaucetModule()
Expand Down
4 changes: 4 additions & 0 deletions data/static/codefixes/adminSectionChallenge_4.ts
Expand Up @@ -159,6 +159,10 @@ const routes: Routes = [
path: 'juicy-nft',
component: NFTUnlockComponent
},
{
path: 'wallet-web3',
loadChildren: async () => await loadWeb3WalletModule()
},
{
path: 'bee-haven',
loadChildren: async () => await loadFaucetModule()
Expand Down
4 changes: 4 additions & 0 deletions data/static/codefixes/scoreBoardChallenge_1_correct.ts
Expand Up @@ -159,6 +159,10 @@ const routes: Routes = [
path: 'juicy-nft',
component: NFTUnlockComponent
},
{
path: 'wallet-web3',
loadChildren: async () => await loadWeb3WalletModule()
},
{
path: 'bee-haven',
loadChildren: async () => await loadFaucetModule()
Expand Down
4 changes: 4 additions & 0 deletions data/static/codefixes/scoreBoardChallenge_2.ts
Expand Up @@ -159,6 +159,10 @@ const routes: Routes = [
path: 'juicy-nft',
component: NFTUnlockComponent
},
{
path: 'wallet-web3',
loadChildren: async () => await loadWeb3WalletModule()
},
{
path: 'bee-haven',
loadChildren: async () => await loadFaucetModule()
Expand Down
4 changes: 4 additions & 0 deletions data/static/codefixes/scoreBoardChallenge_3.ts
Expand Up @@ -155,6 +155,10 @@ const routes: Routes = [
path: 'juicy-nft',
component: NFTUnlockComponent
},
{
path: 'wallet-web3',
loadChildren: async () => await loadWeb3WalletModule()
},
{
path: 'bee-haven',
loadChildren: async () => await loadFaucetModule()
Expand Down
102 changes: 102 additions & 0 deletions data/static/contractABIs.ts
Expand Up @@ -465,3 +465,105 @@ export const nftABI = [
type: 'function'
}
]
export const web3WalletABI = [
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: 'address',
name: 'culprit',
type: 'address'
}
],
name: 'ContractExploited',
type: 'event'
},
{
inputs: [
{
internalType: 'address',
name: '_who',
type: 'address'
}
],
name: 'balanceOf',
outputs: [
{
internalType: 'uint256',
name: 'balance',
type: 'uint256'
}
],
stateMutability: 'view',
type: 'function'
},
{
inputs: [
{
internalType: 'address',
name: '',
type: 'address'
}
],
name: 'balances',
outputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256'
}
],
stateMutability: 'view',
type: 'function'
},
{
inputs: [
{
internalType: 'address',
name: '_to',
type: 'address'
}
],
name: 'ethdeposit',
outputs: [],
stateMutability: 'payable',
type: 'function'
},
{
inputs: [
{
internalType: 'address',
name: '',
type: 'address'
}
],
name: 'userWithdrawing',
outputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256'
}
],
stateMutability: 'view',
type: 'function'
},
{
inputs: [
{
internalType: 'uint256',
name: '_amount',
type: 'uint256'
}
],
name: 'withdraw',
outputs: [],
stateMutability: 'nonpayable',
type: 'function'
},
{
stateMutability: 'payable',
type: 'receive'
}
]
11 changes: 11 additions & 0 deletions frontend/src/app/Services/keys.service.ts
Expand Up @@ -60,4 +60,15 @@ export class KeysService {
})
)
}

walletAddressSend (walletAddress: string) {
const endpoint = this.host + '/walletExploitAddress'
const params = { walletAddress }
return this.http.post(endpoint, params).pipe(
map((response: any) => response),
catchError((err) => {
throw err
})
)
}
}
8 changes: 8 additions & 0 deletions frontend/src/app/app.routing.ts
Expand Up @@ -47,6 +47,10 @@ const loadFaucetModule = async () => {
const module = await import('./faucet/faucet.module')
return module.FaucetModule
}
const loadWeb3WalletModule = async () => {
const module = await import('./wallet-web3/wallet-web3.module')
return module.WalletWeb3Module
}
// vuln-code-snippet start adminSectionChallenge scoreBoardChallenge
const routes: Routes = [
{ // vuln-code-snippet neutral-line adminSectionChallenge
Expand Down Expand Up @@ -209,6 +213,10 @@ const routes: Routes = [
path: 'juicy-nft',
component: NFTUnlockComponent
},
{
path: 'wallet-web3',
loadChildren: async () => await loadWeb3WalletModule()
},
{
path: 'bee-haven',
loadChildren: async () => await loadFaucetModule()
Expand Down
62 changes: 62 additions & 0 deletions frontend/src/app/wallet-web3/wallet-web3.component.html
@@ -0,0 +1,62 @@
<mat-card class="mat-elevation-z6">
<div class="header_container">
<h1>Crypto Wallet</h1>
<div class="metamask-button">
<button
mat-raised-button
color="accent"
type="button"
(click)="handleAuth()"
>
<span *ngIf="!session">Connect your MetaMask</span>
<span *ngIf="session"
>{{ userData.address.substring(0, 6) }}...{{
userData.address.slice(-6)
}}</span
>
</button>
</div>
</div>
<p>
<b>
<span>Your Wallet Balance:</span>
<span class="confirmation"> {{ walletBalance }} ETH</span>
</b>
</p>
<div>
<mat-form-field style="width: 100%" color="accent" appearance="outline">
<mat-label>Enter amount:</mat-label>
<input
matInput
placeholder="Enter ether amount to deposit/withdraw"
type="number"
id="inputAmount"
[(ngModel)]="inputAmount"
aria-label="Text field for the withdrawal amount"
/>
</mat-form-field>
<h5 class="error">{{ errorMessage }}</h5>
</div>
<div class="dwbutton_container">
<button
type="submit"
class="deposit_withdraw_button"
mat-raised-button
color="primary"
aria-label="Button to deposit"
(click)="depositETH()"
>
Deposit
</button>
<button
type="submit"
class="deposit_withdraw_button"
mat-raised-button
color="warning"
aria-label="Button to withdraw"
(click)="withdrawETH()"
>
Withdraw
</button>
</div>
</mat-card>
38 changes: 38 additions & 0 deletions frontend/src/app/wallet-web3/wallet-web3.component.scss
@@ -0,0 +1,38 @@
.header_container {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
}

.dwbutton_container {
display: flex;
gap: 12px;
justify-content: space-between;

}

mat-card {
display: block;
margin-left: 30%;
margin-right: 30%;
}

mat-form-field {
padding-top: 10px;
width: 100%;
}

.form-container {
min-width: 350px;
}

.deposit_withdraw_button {
width: 100%;
}

.heading {
background: rgba(0, 0, 0, 0.2);
font-size: x-large;
justify-content: center;
padding: 12px 20px;
}