写在前面
学二进制、pwn,pwnable.kr是一个必须要刷的网站,所以开一篇文章专门记录自己的刷题历程
其实网上很多都有,但我这里主要记录各题的思路,不写详细的解法,也主要用于自己的归纳总结,do it yourself,才能学到更多
对我所说的思路有不了解或有不同的看法的,欢迎email我 lin.giglf@gmail.com 一起讨论
不定期更新
Toddler’s Bottle
这个章节做完有点久了。。然后才来补思路,如果有什么错误欢迎联系我 ↑
fd
知道linux 下stdin=0
stdout=1
stderr=2
collision
学会怎么用python构造非ascii字符的输入
bof
一个简单的溢出,覆盖相邻变量的值
flag
这其实是一道逆向题。。直接逆就好
passcode
scanf没有加取地址符,debug发现能控制passcode1的值,然后可以通过覆写plt达到目的
random
随机数种子固定,每次生成随机数一样
input
这题挺有意思的,写程序执行实现每个阶段的要求,需要了解一些socket相关的知识还有Linux软连接,很有趣!
leg
考察arm汇编的阅读,要知道一点,pc的值为当前地址+8
mistake
打开password给fd赋值时没有用括号,优先级问题从读文件变成了stdin
shellshock
给了一个特定版本的bash,这是一个cve,(CVE-2014-6271),bash是不会继承定义的函数,但是会继承定义的环境变量。而在该版本及以下的bash当中,对环境变量函数的解析在函数定义完毕后并不会停止。便导致了这个漏洞。
coin1
通过二分法找出那枚硬币,关键其实是怎么编写与服务器通信的脚本。It’s a good way to learn pwntools.
blackjack
阅读代码,发现输入bet money时能溢出,You just need to win one time.
lotto
看检测代码部分,双层循环,则只要其中一位能在random中找到就行了
cmd1
程序过滤了sh, tmp, flag
于是/bin/cat fla* ,可以用通配符来解决过滤的flag
cmd2
过滤了/
,还删除了对应的环境变量,无法直接cat了,flag依旧可以通过通配符解决。
网上搜wp看到了很多种思路
- cd 到根目录,通过$(pwd)构造
/
的 - 把命令编码成八进制,通过echo解决的
uaf
use after free。在调用的时候,没有检测是否对象已经free,free了后的内存可以任意写,此时写入getshell的地址,则再次调用时就会调用到getshell的函数。
codemap
让学习的是ida的IDC脚本编写,当然可以选择使用python,已经提示了注意某个地址寄存器的值,只要在循环每次读入寄存器的值,找出符合的那几个数即可。
memcpy
这题关键是要让程序跑通,主要就是那段内嵌汇编要正常运作不能崩。
内嵌汇编中,movntps是对xmm进行操作的,xmm是128bits寄存器,16字节,则要求空间要16字节对齐。每次输入满足对齐规则的空间大小。
asm
考shellcode的编写,嗯,pwntools的确是个好东西
unlink
链表中,在unlink一个单位时,很容易出问题
例如,有一链表 A <-> B <-> C
unlink(B)时,
1 | bk = B->bk; |
如果把B->bk、B->fd改写了,则可以改写任意地址的内容。
例如,假设bk指针在结构体第8字节,改写fd = B->fd = address-8
则fd->bk = address-8+8 = bk = B->bk
可以把address地址改写,即可以改写任意地址的内容
blukat
password是没有权限去读的,但是在运行的blukat有读的权限并且我们可以运行blukat,在调试中直接就可以看到读到buf中的password内容,而且这个password内容还伪装了一把permission denied。。
horcruxes
说明需要rop,很容易找到溢出点,并且没开canary,第一想法是溢出gets直接跳到open flag那里就可以得到flag了。但是试了好一会都没成功,后来才发现在ropme的函数里地址都包含0x0A,即\n
,gets是会截断的。因此只能反复跳到ABCDEFG并计算出sum值最后再call ropme去满足条件获取flag
Rookiss
brain fuck
这题属于GOT表替换,brainfuck的指令能随意移动指针,可以移动到GOT表做函数替换
md5 calculator
这题的关键点,找到溢出点,base64编码跟原码长度为4:3,存在溢出
但开了Canary保护,能看到在开头验证码生成时用了对应的cookie,所以可以通过验证码反推出cookie,绕过Canary保护
simple login
溢出限制了长度,只能溢出到ebp,ret处理不了,但这里在auth函数的ret后,紧接着是main函数的ret,理清思路后可以利用
otp
这个题。。。没接触过根本想不到,ulimite -f 0
限制文件大小,使得密码为0
ascii_easy
这题是我花时间最长的一题了,上网搜了wp,然后发现题目改过,虽然思路差不多,就是构造ascii的shellcode,但一直也没成功。后来github搜到一个解法,发现是函数调用问题,对于系统调用的跟通常的函数调用有点不一样。
例如call execve,可以参考 http://shell-storm.org/blog/Return-Oriented-Programming-and-ROPgadget-tool/
然后就是,想方设法构造在ascii范围内的shellcode,并且可以通过环境变量的方式做一个/bin/sh的别名链接,使得我们不需要构造出/bin/sh的地址。但实际想要构造也能成功,通过地址的变换,再找几个rop_chain实现
tiny_easy
一个只包含几条指令的binary,简单调试可得,最后call的是argv[0],并且栈可执行,但是有aslr
通常,直接启动执行argv[0]是程序执行路径。那么这里有个知识点,可以通过execl进行启动,l参数启动的时候argv[0]是可以自定义的,于是我们可以通过argv往栈上写shellcode,但是call的地址不确定,我们可以通过栈喷的方式,在shellcode前填充大量的slide code(例如nop),于是便可以跑到shellcode上getshell。
技巧:调试通过exec系列启动的程序,gdb中set follow-fork-mode child
可令调试程序执行跟进到子进程,catch exec
可以挂接gdb到通过exec启动的程序上,在该程序上下断点。
fsb
简单分析即可知道存在format string (格式化字符串)漏洞
emmm printf不仅可以用来泄漏地址,还可以用来写入地址,printf包含一个%n的占位符,这个参数的作用是
不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量。
于是可以通过这个这个方式向栈上写入地址,而因为key的地址是可以获得的(通过printf泄漏或者直接获取都可以,因为key位于.bss段 并且程序没开启aslr),便可以向栈上写入key的地址
接下来便可以用同样方法覆写key的地址或者直接泄漏key的值了
dragon
RPG游戏,试验了一下怎么都不可能正常的打败dragon的,但是我们发现dragon每一轮都会给自己加血,并且dragon的HP储存是个char,那么就恰好存在一个溢出,溢出到负数便可以触发打败dragon
那么怎么利用?dragon被打败后会free掉,同时malloc一个同样大小的buf,而后面居然还调用free掉的dragon里的函数,这就是一个UAF,复写dragon中的func到system(“/bin/sh”)就OK了
syscall
linux kernel pwn,实现了一个kernel module,而这个kernel module包含一个bug,任意地址写。
因为在kernel对任意地址写可以达到进行任意的系统调用,例如通过commit_creds(prepare_kernel_cred(0))
进行提权。通过 cat /proc/kallsyms便可以查看两个系统调用的符号地址。
最后有一个需要绕过的点,kernel module实现的系统调用会对小写字符大写,而符号地址当中便包含一个0x6c,我用了别人wp的一个方法,向该地址前面的内存填充nop指令,然后跳转到0x60之前的地址,从而绕过该限制。另外也有师傅通过汇编实现了真正的全地址任意写,看了一下网上的wp,简直就是各显神通。
最后提权后直接cat /root/flag就OK了
Crypto1
密码学题目,关于AES128CBC的使用漏洞,题目会给出由个人提供输入AES128_CBC加密结果,key、IV不知
因为在CBC模式下,16byte的分组有,当前n 16 byte的信息前缀相同时,加密出来的前n 16也是相等的
这个设计到分组密码与CBC模式的弱点
因此当有段不明信息secretmessage
,可以通过比较
AES128Encode(---------------s
)
AES128Encode(---------------*
)
构造最后一位*,进行爆破比对,从而得出最终明文
echo1
超大的栈溢出,什么保护都没有,直接往栈上写shellcode然后再通过bss作为跳板jmp rsp就可以getshell
要注意一点就是pwntools写shellcode时,shellcraft.sh
是32位的shellcraft.amd64.sh
是64位的
echo2
shellcode不能用shellcraft的了,因为无论哪种利用方式,输入长度都限制在24以下,所以可以从exploitdb上找shellcode,用fsb泄漏出shellcode地址,然后通过uaf利用调用shellcode
这题实际也很简单,感觉自己花了很多时间是在找bug和复习fsb上了T_T
rsa_calculator
需要比较耐心的逆向才能找到bug。。。
这题关键漏洞都在rsa_decrypt函数里,包含有fmtstr和stack overflow
程序只开了canary
所以,思路是通过fmtstr leak canary,然后通过stack overflow写ret
虽然binary提供了system函数,但是最简单还是直接用shellcode了
这题需要注意的点是decrypt的时候几个buffer 从hex to byte的操作
由于1024的buf overflow到了520的buf,520的buf再stack overflow
而520的buf是由1024的buf hex2byte生成的,所以overflow到520buf的部分需要进行两次encode(‘hex’)的操作,然后就可以构造溢出data了
alloca
很容易发现size可以小于0,但是怎么利用呢?
一个思路,先寻找有哪些操作可以往栈上写
当发现只有g_canary可以时,去找写到栈上的地方与ebp-4的关系
能够列出公式,最后求解出size
最后通过env上填充callme的地址,跳转过去,多次启动一定几率下可以getshell