用户
搜索

该用户从未签到

i春秋-核心白帽

Rank: 4

21

主题

85

帖子

524

魔法币
收听
0
粉丝
3
注册时间
2017-7-29
发表于 2018-9-19 19:45:44 46066

0x00 前言

最近在学pwn,发现了一个很不错的一个刷题的网站http://pwnable.kr/ 里面是以闯关的形式来做题,里面涉及到了很多linux下的知识,边做题边学,会发现进步的很快。这里就和大家分享一下自己的解题思路和一些自己的思考,如有什么写的不好的地方,请大家斧正~~

0x01 fd

fd是文件描述符的意思,百度百科上的概念是:

内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。

这里需要记住三个重要的数值:
0 表示标准输入
1 标准输出
2 标准错误

例如:read(0,buf,20) 表示输入20个字节到buf缓冲区里,也就是read函数调用以后会在屏幕中等待我们的输入,并存储在缓冲区里(标准输入)
write(1,buf,20)表示输出20字节到buf,并显示在屏幕中(标准输出)

然后再看下题:
用ssh连接上以后,ls发现有三个文件

题目的意思是接收一个参数的输入,转换为int型数值,经过read函数到缓冲区里,比较了缓冲区里面的值是否和字符串LETMEWIN相等,相等就输出flag

分析:这里的fd是我们输入的值,那么我们令fd为0,就可以使得read接收我们在屏幕的输入,并存储在缓冲区当中,所以接受输入的时候输入LETMEWIN就行了

第一步先输入参数0x1234的十进制值,使得fd为0

此时屏幕就会等待我们的输入,这里就输入LETMEWIN


这样就成功拿到flag,所以这里还是要理解文件描述符的概念,这里可以用man read命令来查看帮助文档,还是非常有帮助的

0x02 collision

先看看题,题目接收一个passcode的参数值,将这个值传入check_password函数中进行运算,判断是否与hashcode的值相等,相等就输出flag

试着输入一些值

分析:先来看看check_password函数
第一步,int *ip = (int*)p;   //将输入的char类型的字符转换为int类型指针的,也就是十六进制转十进制(四字节)
第二步,for(i=0; i<5; i++){   res += ip[i];   },将输入的数值分为五组,并把每组的值相加赋值给int型的res变量

构造payload:

4字节分为5组,总共20个字节,所给的hashcode=0x21DD0EC
那么我们可以构造五组的数据:0x01010101*4+0x1DD905E8 = 021DD0EC

发送payload

这里选择用python来写入,如果是在本地的话也可以选择使用pwntools来写入
python发送数据的固定用法就是下面的形式,记得就好了。
python -c "print '\xe8\x05\xd9\x1d'+'\x01\x01\x01\x01'*4"|xargs ./col
或者
python -c "print '\xe8\x05\xd9\x1d'+'\x01'*16"|xargs ./col
记得这边是小端顺序输入
构造payload后得到flag

0x03 bof

这道题就是标准的pwn题了,把文件下载下来查看代码

是一个简单的栈溢出,溢出就在gets函数处,

即这个函数不检查输入的边界,输入过长的数据会导致输入的值溢出覆盖到别的数据

分析:这里得到flag的途径是key == 0xcafebabe,key为func函数的形参,在main函数中调用了这个函数,但是发现他传入的值已经为0xdeadbeef,所以我们需要做的就是覆盖func函数的参数为0xcafebabe,就可以读到flag了。

现在的栈的分布情况:

解题步骤
1、IDA静态分析


2C = 44,a1 = ebp+8。再加上ret addr的4byte,总共52byte(这里不需要考虑0xcafebabe自身的长度)

2、qira中动态分析

先输入一堆a,报段错误,在web页面中查看情况

要覆盖到0xdeaddeef处,总共的字符数为16*3+4 = 52byte

发送payload

两种方法发送shellcode,pwntools和命令行python

1、pwntools

2、python -c
(python -c "print '\x61'*52+'\xbe\xba\xfe\xca' ";cat) | ./bof


解题的时候就把管道符后面的./bof替换成 nc pwnable.kr 9000就行了

getshell

0x04 flag

这道题是一个二进制逆向题,首先用IDA打开他,发现代码就行了混淆,估计是加了壳,用xxd命令查看文件的十六进制值

xxd flag | tail打印末尾的数据

看到了upx压缩壳,所以用upx -d解压

IDA静态分析

分析一下main函数

分析一下这些汇编语句:

1、mov edi,offset aIWillMallocAnd
//将字符串赋值给edi寄存器

2、call puts
//调用puts函数,edi的内容为函数的参数

3、mov edi,64h
//edi = 100

4、call malloc
//调用malloc函数,动态开辟一个大小为100byte的堆空间

5、mov [rbp+var_8], rax
//将eax的值赋值给栈中的参数

6、mov rdx, cs:flag
//将flag的偏移段赋值给rdx

7、mov rax, [rbp+var_8]
//参数赋值给rax

8、mov  rsi, rdx,mov  rdi, rax
//rax,rdx作为sub_400320函数两个参数赋值给rsi,rdi

9、call sub_400320
//调用函数并打印

分析完发现flag就在以cs为段寄存器的偏移地址里,双击进去就找到flag

0x05 passcode

这道题的漏洞点利用的就比较巧妙了,用到了got表劫持技术,一般这个技术是配合任意地址写入的漏洞来达到劫持的目的

got表和plt表的知识:
https://blog.csdn.net/qq_18661257/article/details/54694748
got表劫持技术就是把原来需要调用的函数的got表项(如printf函数)劫持成system函数的got表项,这样我们在调用printf函数时就可以直接调用system函数

首先ssh连接上服务器,查看一下源码

分析:看到有三个比较重要的函数:main函数、login函数,welcome函数

main函数中调用了welcome函数和login函数,这里需要记得一个重要的点,welcomde和login函数共用的main函数的栈帧(因为都是在main函数中调用)

代码的大概意思就是接受一个name输入,然后输入passcode1和passcode2,验证是否与if语句里的值相同,但是这里仔细看:scanf函数的第二个参数没有取地址符号&,所以是没办法给passcode的两个参数赋值的

这里就像在初学C语言的时候,没有加上&符号就会导致程序的运行错误

如图,接受的命令行参数被scanf作为地址了,但是这个地址不存在,所以会直接报错Segmentation fault(段错误)

攻击步骤

攻击原理:
1、由于got表是可写的,把其中的函数地址覆盖为我们shellcode地址,在程序进行调用这个函数时就会执行shellcode。
2、在这个程序中,welcome函数和login函数的ebp都是一样的,所以可以在执行login函数时进行填充。

先看看两个函数的栈帧

需要的填充数为0x70 - 0x10 = 96byte,再加上函数的返回地址以及scanf函数的参数


所以payload:'a' * 96 + p32(fflush_got_addr) + str(0x080485e3)
(scanf接受的参数类型是int型)

如下图:0x080485e3是system函数的地址

fflush_got_addr的地址可以使用:objdump -R ./passcode查看

这里就不用pwntools演示了,因为payload就一句话,利用比较简单

这里还可以使用python来发包:
python -c "print ('a'*96+'\x00\xa0\x04\x08'+'134514147')" | ./passcode

另外got表劫持技术还可以用在格式化字符串漏洞上面,参考这里

0x06 random

ssh连接上,查看源代码

分析:代码很简单就只有一个main函数,函数的大概意思是接收一个输入,将输入与前面rand函数产生的随机数异或,判断结果

这里可以很容易看出漏洞点在rand函数上,rand函数没有传入种子,产生的随机数的结果都是一样的
可以看看百度百科的解释:https://baike.baidu.com/item/rand%E5%87%BD%E6%95%B0/5916603

我们可以这样验证:

1、编写代码进行验证,进入gdb调试

2、在rand的函数处下断点,单步步过以后返回值就是rand的随机数的值,也就是eax的值


得到的返回值都是0x6b8b4567,也就是十进制的1804289383

3、因为异或是可逆操作,将1804289383和题目中的0xdeadbeef进行异或,得到的结果作为输入就可以得到答案


这里我们输入这串数字,得到flag

这里原来想的另一种解法是在远程的gdb调试中,在代码if比较处直接改eax值为0xdeadbeef,但是发现并没有得到flag,而是提示Permission denied,求大神告知

0x07 总结

感觉学二进制的过程中,刷题真的是一种很高效的提高自己技术水平的一个方法途径,希望大家多刷题多总结,做题的过程中可以相互学习,有什么问题大家可以在下面评论或者直接加我qq:1179317825

{:7_186:}
学习学习!
使用道具 举报 回复
支持一下~
使用道具 举报 回复
发表于 2018-9-25 18:28:15
使用道具 举报 回复
发表于 2018-10-1 05:10:01
支持一下
路漫漫,
使用道具 举报 回复
发新帖
您需要登录后才可以回帖 登录 | 立即注册