pwnable.kr笔记
pwnable.kr算是pwn入门级别的题目,做一遍记录下大概的知识点。 # 大致流程
- 检查软件的详细信息,得到是32位或64位的ELF。
1
2
3
4
5checksec software
或
file software
或者
binwalk software - 运行软件,了解软件的流程,一般将软件拷贝到本地来调试方便些,可以通过(
scp
)[http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/scp.html] 命令。例如将tiny_easy
拷贝到本地目录内,输入以下命令,再输入密码即可。
1 | scp -P 2222 tiny_easy@pwnable.kr:/home/tiny_easy/tiny_easy . |
- 使用gdb工具调试软件 关闭
1
2
3# 加载软件,不显示额外信息
gdb -q software
# 加载alarm(0x38u);
1
2
3gdb-peda$ handle SIGALRM print nopass
Signal Stop Print Pass to program Description
SIGALRM No Yes No Alarm clock
将代码重新编译成可执行文件,关闭gcc编译器优化以启用缓冲区溢出。
禁用ASLR
1
sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space'
禁用canary:
1
gcc overflow.c -o overflow -fno-stack-protector
pwntools工具
shellcode
通过(pwnlib.shellcraft)[http://docs.pwntools.com/en/stable/shellcraft/i386.html#pwnlib.shellcraft.i386.linux.syscall]
调用系统调用来生成shellcode
: 1
print pwnlib.shellcraft.open('/home/pwn/flag').rstrip()
[Toddler's Bottle]
fd
collision
bof
flag
Papa brought me a packed present! let's open it.
Download : http://pwnable.kr/bin/flag
This is reversing task. all you need is binary
这道题说的很明确,对软件逆向,而且是个packed
软件。
运行软件
random
本题就考察的是对rand函数的理解。随机数生成器需要设置随机种子。如果rand未设置,rand会在调用时自动设置随机数种子为1。rand()产生的是伪随机数,每次执行的结果相同。若要不同,需要调用srand()初始化函数。
利用gdb调试,rand()每次确实生成相同的数0x6b8b4567
。
所以可以利用异或得: 1
key = 0x6b8b4567^0xdeadbeef = 3039230856
unlink
[Rookiss]
otp
tiny_easy
思路
1 | Arch: i386-32-little |
程序将所有保护措施关闭,关键代码 1
2
3
40x8048054: pop eax
0x8048055: pop edx
0x8048056: mov edx,DWORD PTR [edx]
0x8048058: call edx
通过strace
查看错误发生在哪里。 1
2
3
4
5
6➜ tiny_easy strace -if ./tiny_easy
[00007ff68ad5c047] execve("./tiny_easy", ["./tiny_easy"], [/* 66 vars */]) = 0
[69742f2e] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x69742f2e} ---
[????????????????] +++ killed by SIGSEGV +++
[1] 34625 segmentation fault strace -if ./tiny_easy
解题
堆喷射,即在 argv[0] 里面放猜测的栈中的某个地址,然后跳到存在 argv[1…n] 里面的 shellcode. 用大量的滑行区来填充shellcode的前部。只要EIP能落在滑行区就可以执行shellcode。只要部署大量的带有滑行区的shellcode,多次尝试,肯定会有EIP落入滑行区的时候。
1 |
|
dragon
此题需要注意的是dragon结构体的定义。
1 | v5[1] = 1; |
得出的dragon结构体为 1
2
3
4
5
6
7struct dragon{
char * printDragonInfo;
int type;
char HP;
char regeneration;
int damage;
}
而英雄的结构体定义
*ptr = 1;
ptr[1] = 42;
ptr[2] = 50;
ptr[3] = PrintPlayerInfo;
1 | struct hero{ |
打龙时,胜利的条件是
1. *(_DWORD *)(ptrHero + 4) > 0
2. *((_BYTE *)ptrDragon + 8) <= 0
通过正常的流程英雄无法胜利,但是我们注意到,dragon的HP是_BYTE_
类型,也就是有符号的字符型,可以通过汇编代码查看。
1
2
3.text:08048AE6 movzx eax, byte ptr [eax+8]
.text:08048AEA test al, al
.text:08048AEC jg short loc_8048B00jg
表示有符号比较。
龙怪有个回血技能,可以让龙怪的HP
增加,所以我们可以利用这一点,让HP
超过127后溢出,变成负数。
这里选择的策略是,mama dragon
,priest
,3技能龙怪不攻击但是龙怪回血,2技能priest
回蓝,组合为332332332
。
还有注意,dragon
出现是随机但是交替的,需要判断下。最后利用UAF返回到程序中已经给出的system("/bin/sh");
。
1 | from pwn import * |