Defcon qualifier 2015 catwestern(Coding1) WriteUp

Reading time ~1 minute

这题作为这次defcon预选赛中唯一的一道coding题,还是1分,很显然是送分题了,直接连上服务器可以得到如下返回:

$ nc catwestern_631d7907670909fc4df2defc13f2057c.quals.shallweplayaga.me 9999
****Initial Register State****
rax=0xfcf7659c7a4ad096
rbx=0x1df0e8dfe8f70b53
rcx=0x55004165472b9655
rdx=0x1aa98e77006adf1
rsi=0x949a482579724b11
rdi=0x1e671d7b7ef9430
r8=0x3251192496cee6a6
r9=0x278d01e964b0efc8
r10=0x1c5c8cca5112ad12
r11=0x75a01cef4514d4f5
r12=0xe109fd4392125cc7
r13=0xe5e33405335ba0ff
r14=0x633e16d0ec94137
r15=0xb80a585e0cd42415
****Send Solution In The Same Format****
About to send 74 bytes: 
hŒråRI‡ÔA]HÿÊIÇ¢éNhIÿÊHÿÃHÎIÇ^…6H¤Ã
                                       MÃI÷ëH)ðHÆQØ8eHÿÀIÁÕH5Œm'Ã^C

即这里是给出了一些寄存器的初始状态,让我们执行下面给的机器指令,那显然,相比于写个解释器模拟执行,我们写个程序直接能运行这段指令是最好的。这里如果用汇编写可能会方便点吧,不过鉴于好久没写过汇编的了,用C++写了个内嵌汇编的:

#!/usr/bin/env python
#encoding:utf-8

import zio
import pwn
import commands

TARGET = ('catwestern_631d7907670909fc4df2defc13f2057c.quals.shallweplayaga.me', 9999)


io = zio.zio(TARGET)
io.readline()
regs = io.read_until(['****Send Solution In The Same Format****']).split('n')[:-1]

while True:
    io.read_until('bytes: n')
    ops = io.read_until_timeout()
    if ops[-1] != 'xc3':
        print "Error, not end with xc3."
        exit(1)
    print ''
    print len(ops)

    regs = [x.split('=') for x in regs]
    ops = 'x48xb8' + zio.l64(int(regs[0][1], 16)) + ops

    # headers
    cpp = open('run.cpp', 'w')
    cpp.write('''
    #include <stdio.h>

    using namespace std;

    int main()
    {
    char *ops = "%s";
    ''' % ''.join(['\x%02x' % ord(x) for x in ops]))

    for x in regs:
        # if int(x[1], 16) > int('0xffffffff', 16):
            # x[1] = str(int(x[1], 16) & 0xffffffff)
        cpp.write('__asm__("mov $%s, %%%s");n' % (x[1], x[0]))

    # pwn.o
    # codes = pwn.disasm(ops).split('n')
    # for x in codes:
    #     cpp.write('__asm__("%s");n' % x.split(' ' * 6)[-1].strip())
    cpp.write("((void (*)())ops)();n")

    for x in regs:
        cpp.write('__asm__("push %%%s");n' % x[0])

    i = 6
    for x in regs:
        # cpp.write('printf("%%%d$p\n");n' % i)
        cpp.write('printf("0x%%%d$llx\n");n' % i)
        # cpp.write('printf("0x%%%d$016llx\n");n' % i)
        i += 1

    # footers
    cpp.write('''
        return 0;
    }
    ''')

    cpp.close()

    commands.getstatusoutput('g++ -z execstack -fno-stack-protector -Wall -o ./run ./run.cpp')
    status, output = commands.getstatusoutput('./run')
    output = output.split('n')[::-1]

    i = 0
    for x in regs:
        output[i] = x[0] + '=' + output[i]
        i += 1

    io.writelines(output)
    io.readline()
# print io.readline()
# print io.read_until_timeout()

这里中间产生的C++代码类似:

#include <cstdio>

using namespace std;

int main()
{
char *ops = "……";
__asm__("mov $0x365a6103367515ed, %rax");
__asm__("mov $0x3cb1a6fff5b038b6, %rbx");
__asm__("mov $0x2a5e4d432e3810e7, %rcx");
__asm__("mov $0x3fc79069d112d35e, %rdx");
__asm__("mov $0xe9b6862f68ddc08b, %rsi");
__asm__("mov $0xc9bb5638f34a4ed2, %rdi");
__asm__("mov $0x1eea6b2bcfa19f55, %r8");
__asm__("mov $0xb48d0fe2a6217fcd, %r9");
__asm__("mov $0x7ff063bcf81b25d7, %r10");
__asm__("mov $0x7ecfd1750b003532, %r11");
__asm__("mov $0x2e45b91b25474403, %r12");
__asm__("mov $0xb9661518b82c711, %r13");
__asm__("mov $0x3f397cafd35489db, %r14");
__asm__("mov $0x1d0dc0438a2a9b1f, %r15");
((void (*)())ops)();
__asm__("push %rax");
__asm__("push %rbx");
__asm__("push %rcx");
__asm__("push %rdx");
__asm__("push %rsi");
__asm__("push %rdi");
__asm__("push %r8");
__asm__("push %r9");
__asm__("push %r10");
__asm__("push %r11");
__asm__("push %r12");
__asm__("push %r13");
__asm__("push %r14");
__asm__("push %r15");
printf("%6$pn");
printf("%7$pn");
printf("%8$pn");
printf("%9$pn");
printf("%10$pn");
printf("%11$pn");
printf("%12$pn");
printf("%13$pn");
printf("%14$pn");
printf("%15$pn");
printf("%16$pn");
printf("%17$pn");
printf("%18$pn");
printf("%19$pn");

    return 0;
}

即先将寄存器初始设置好,然后运行所给指令,然后将所有寄存器压栈,通过printf输出。然后这里要注意的是,所给指令最后一句几乎可以肯定说是ret,所以可以很方便的直接call上去就好,但是由于编译出来call的时候,是先将地址移到rax中,然后再call,所以说我们需要在所给指令前面加上一段指令重新设置rax的值,也即上面Python代码中的:

ops = 'x48xb8' + zio.l64(int(regs[0][1], 16)) + ops

然后这题比较蛋疼的是,最开始主办方题目弄错了点啥,搞得一直过不了,各种无语,最关键的是,当时题目有问题的情况下有队过了,所以无奈啊……

挂载网络文件夹后网络故障时文件操作命令卡死

挂载 NFS 或者 Samba 的时候,经常会由于网络故障导致挂载好的链接断掉。此时如果尝试进行 ls、cd、df 等各种命令,只要与此目录沾上边,就会卡住。如果使用了类似 oh-my-zsh 这种配置的,只要在网络目录中,弹出命令提示符前就会直接卡住。这个时候第一反应就是...… Continue reading

路由折腾记 第四弹

Published on September 02, 2017