0x01 get_shell
- 纯新手题。
- Linux系统 nc连接到题中给的地址,然后
cat flag
即可。
0x02 CGfsb
考察格式化字符串漏洞。
emmm Freebuf上有很详细的格式化字符串漏洞原理及利用的讲解,链接如下。
- 这个具体偏移可以手动测出来。
- 测出来为10,所以exp中就用
%10$n
了。
pwnme的地址在IDA中就能找出来,是
0x0804A068
所以exp为:
1 | #coding:utf-8 |
补充
- 后来在看一篇文章的时候发现了一个点。
- 改进后的exp如下:
1 | from pwn import * |
0x03 when_did_you_born
- 考察栈溢出、变量覆盖。
var_20 就是v4, var_18就是v5,他俩之间隔了8个字节。
根据逻辑,第一次我们输入一个不是1926的数字,然后通过危险函数
gets
将读入的数据存入v4, 通过溢出来覆盖v5,让v5的值为1926从而cat flag
exp如下:
1 | from pwn import * |
0x04 hello_pwn
- 考察的和上一个题几乎一样。。。
还是直接覆盖..
exp如下:
1 | from pwn import * |
0x05 level0
- 考察栈溢出。
- 很明显的栈溢出
- 存在
/bin/sh
而且有被system函数
调用
- 所以 exp如下:
1 | from pwn import * |
0x06 level2
- 典型的栈溢出。
存在
/bin/sh
但是没有调用。存在
system函数
但是是用来echo
一些信息的。所以直接把
system函数
的参数修改成/bin/sh
就好了。exp如下:
1 | # -*- coding: UTF-8 -*- |
- 为什么payload是上面那个顺序?
- 答:
在32位程序运行中,函数参数直接压入栈中
调用函数时栈的结构为:调用函数地址->函数的返回地址->参数n->参数n-1->···->参数1
而在64位程序运行中,参数传递需要寄存器
64位参数传递约定:前六个参数按顺序存储在寄存器rdi, rsi, rdx, rcx, r8, r9中
参数超过六个时,从第七个开始压入栈中
0x07 guess_num
- var_30就是 v8, seed就是seed, 可以进行覆盖,间隔为0x20个字节。
思路一
覆盖seed为1, 模拟执行srand(1),然后在exp中模拟得到v7的各值进行输入。
但是需要知道该程序的libc。
可以通过如下方法得到libc版本。
方法一
- 利用pwntools的ELF模块。
方法二
ldd
命令。
- 思路一的exp如下:
1 | from pwn import * |
思路二
- 覆盖seed, 然后直接求出10次
rand()%6+1
,得到如下输出。
- exp如下:
1 | from pwn import * |
0x08 cgpwn2
- 观察字符串发现并没有
/bin/sh
,但是有对bss段的name的操作,可以通过将/bin/sh
写入name,然后构造payload。
在32位程序调用函数时栈的结构为:调用函数地址->函数的返回地址->参数n->参数n-1->···->参数1
所以随便找一个返回地址
0x0804854D
exp如下:
1 | from pwn import * |
0x09 string
- 题目宛如玩RPG游戏。
- 先是给了你俩secret 让你去打龙,
secret[0]
就是v3的首地址,后面会用到。
- 然后让你输入角色名字来创建角色。
- 问你往哪走, 很明显根据逻辑需要走
east
- 让你给它个地址,然后输入你的愿望,这里有明显的格式化字符串漏洞
printf(&format, &format);
最后如果
*a1 == a1[1]
即 最开始的v3[0]
= 85,巫师就会帮助你,你就可以自己创造一个v1函数
来执行了,这个函数肯定要创造成能拿到shell的函数。目标地址直接传给了v2, v2和format相连。
_isoc99_scanf("%s",&format);
到format
的偏移为8,但是目标地址是存入v2了,所以实际偏移应该为8-1=7shellcode就是通用的shellcode了,具体看下面链接。
- exp如下:
1 | from pwn import * |
0x10 int_overflow
- 考察整数溢出漏洞。
- 这是个模拟登陆系统。
- 俩
read函数
都没有溢出点,接着查看check_passwd
函数。
发现了危险函数
strcpy
,s(即passwd)
的空间明显大于dest
的空间,可以通过这里进行溢出。但是要进入这个
else
语句,需要v3(即passwd的长度)
大于3 小于等于8,但是很明显这个长度根本不够写payload
,所以要在这里进行整形溢出。查看汇编语言可以看到
passwd
的长度是用al
寄存器来传值的,而al
寄存器是8位寄存器,传值的范围为0~255
,超过这个范围就会造成溢出。实际长度256的话,传值以后为0, 257->1, 258->2 …以此类推。
所以我们只需要让这个
s(即passwd)
的长度在260~264之间即可。查找字符串能找到
cat flag
来到对应位置,是一个后门函数。
后门函数的地址为
0x0804868B
dest
距离ebp
的偏移为0x14
,覆盖ebp
需要4个字节,所以得到payload为:payload = 'a'*0x14 + 'a'*4 + p32(0x0804868B) + 'a'*(260-0x14-4-4)
payload不唯一, 最后那个地方,260~264都可以。
exp如下:
1 | from pwn import * |
0x11 level3
这题是
Jarvis OJ - [XMAN]
的原题,但是在攻防世界平台上面出了点bug,题目没给全(少了libc-2.19.so),而且远程怎么都跑不出来。原题链接:
- 以原题为例吧。
read函数
位置存在明显的栈溢出,但是这个题和level2
不同,level2
程序中存在system函数
和/bin/sh
,只是system函数
用来echo
一些信息,/bin/sh
没有被调用。但是这道题目程序中没有
system函数
,也不存在/bin/sh
。由于题目给了libc文件,考虑ret2libc。
正常的溢出思路如下。
但是由于不知道
sys_addr
和bin addr
的值,我们要想办法知道这俩的值。但是我们可以利用
函数在内存中的地址和libc文件中的偏移的差相等
,通过程序中的已有函数,比如read
和write
来获得这个偏移差。而且给了libc文件,我们就能知道system函数
和/bin/sh
在libc文件中的地址,从而通过sys_addr - sys_libc == write_addr - write_libc == 偏移差offset
,得到sys_addr
,同理可得bin addr
。曾试了好久能不能直接把
writegot
的值直接print
出来,然而并没有成功,可能因为我太菜了,也可能是因为这个办法不可行。有一些技术性的文章,对做这个题目挺有帮助的,强烈建议看一看第一篇。
- 这道题目用到了这么一个点。
- 基本思路已经很清晰了。
在32位程序运行中,函数参数直接压入栈中
调用函数时栈的结构为:调用函数地址->函数的返回地址->参数n->参数n-1->···->参数1
- 所以我们要想办法构成这种形式,我们的调用函数即
write函数
,后面的参数都是传给这个write函数
的,调用完毕以后返回到我们的函数的返回地址
。
- 从而exp如下:
1 | # encoding:utf-8 |
后续补充
后来在刷BUUCTF的时候写了一个能打通的EXP
1 | from pwn import * |