Directorio de artículos
1. Base de tipo débil de PHP
Introducción:
Un lenguaje débilmente tipado no tiene restricciones en el tipo de datos de una variable. Puede asignar una variable a cualquier otro tipo de variable en cualquier momento, y la variable también se puede convertir a cualquier otro tipo de datos. En este momento, la conversión de tipo, la comparación de diferentes tipos y el paso de parámetros irrazonable provocarán resultados de ejecución inesperados y evitarán las defensas.
1. Tipos débiles de operadores de comparación
Para PHP, hay dos operadores de comparación ==
y===
- ==: al comparar, el tipo de cadena se convertirá primero en el mismo y luego se comparará
- ===: al comparar, primero juzgará si los tipos de las dos cadenas son iguales y luego comparará
Al usar "==", si compara un número y una cadena o compara una cadena que involucra contenido digital, la cadena se convertirá en un valor y la comparación se realizará de acuerdo con el valor, que durante mucho tiempo ha llevado al tipo débil problema de comparación de valores. Las situaciones comunes son las siguientes:
-
defecto de comparación hash
示例: "0e861580163291561247404381396064" == "0e509367213418206700842008763514" //true 导致这种问题产生的原因在于,hash字符串以0开头,会认为这是一个数字,然后解析为0*10^n,最终两变得的结果都为0,所以判断结果为true。
-
Error de comparación de conversión hexadecimal
示例: "0x1e240"=="123456" //true 导致这个问题是原因也是由于php将0x1e240识别为数字,就会先将0x1e240准换为整数在进行比较。
-
conversión de tipo
<?php $test=1 + "10.5"; // $test=11.5(float) $test=1+"-1.3e3"; //$test=-1299(float) $test=1+"bob-1.3e3";//$test=1(int) $test=1+"2admin";//$test=3(int) $test=1+"admin2";//$test=1(int) ?> PHP手册:当一个字符串被当作一个数值来取值,其结果和类型如下: 如果该字符串没有包含’.’,’e’,’E’ 并且其数值值在整形的范围之内该字符串被当作 int 来取值,其他所有情况下都被作为 float 来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为 0。
-
suplantación de identidad booleana
示例情况: $data ={ user:true;pass:true} if ($data['user'] == 'admin' && $data['pass']=='secirity'){ print_r('logined in as bool'."\n"); } //运行结果:logined in as bool 原理解释: 当我们传入的user和pass=true时,会认为时采用的布尔类型的数值进行比较,就会将"admin"和"secruity"转换为布尔型进行比较,而在PHP中,只有0、false、0.0、不包含任何元素的数组、不包含任何变量的对象、null会被准换为0(false),其他的都会被准换位1(true)。所以最终的结果就是if(1=1 && 1=1),结果为true.
-
problema de conversión digital
示例1: $user_id = ($_POST['user_id']); if ($user_id == "1") { $user_id = (int)($user_id); #$user_id = intval($user_id); $qry = "SELECT * FROM `users` WHERE user_id='$user_id';"; } $result = mysql_query($qry) or die('<pre>' . mysql_error() . '</pre>' ); 在这里,当我们传入的数字ID=0.9999999999999999999999,在进行if判断的时候,会将ID转换为1继进行判断,而在查询的时候,数据库会进行向下取整,认为ID=0,从而查询ID=0的用户数据。 示例2:intval强制转换的弱类型问题 if (intval($qq) === '123456') { $db->query("select * from user where qq = $qq") } 如果采用上述方法,intval将转换所有数字直到遇到非数字为止,随意如果我们传入123456 union select version(),inval($qq)的值将会是123456,但是在查询的时候,由于没有使用intval准换后的ID,就导致了注入。
2. Funciones con problemas de tipos débiles
-
MD5(),sha1()
问题:这两个函数不能处理数组,对于传入的数组,返回结果为null,比如下面这种情况,就会导致null==null,结果为true. $str = array('123' =>123 ); $test=array('234' =>234); if(md5($str)==md5($test)){ echo 'success.......'; }
-
strcmp()
这个函数的作用是比较两个字符串并且区分大小写 当字符串1大于字符串2就返回>0,当字符串1小于字符串2就返回<0,相等则返回0 示例:strcmp($str1,$str2) 绕过方法:通过传入数组的方法,让该函数处理时发生错误,返回结果0,导致绕过。 示例情况: <?php $POST=$_POST[name]; //POSTdata: name[]=1 $pass1="ASDSADSADAD"; if(isset($_GET['pass'])){ if(strcmp($_GET['pass'],$pass1)==0){ echo "success,233"; }else{ echo " fail,322"; } } ?> //result : success,233
-
cambiar()
问题在于switch选择的时候,处理的变量会被强转为int类型。 <?php $a=$_GET['$a']; switch ($a) { case 1: echo "error"; break; case 2: echo "success"; break; } ?> //当我们传入2abcdef时,输出结果为:success
-
en_matriz()
问题点: 函数格式 in_array(需要在数组内搜索的数值,被搜索的数组,一个可选参数,设置TURE检查数据和数组值类型是否相同),这个函数的作用是检查数组中是否存在某个值,当没有最后的检测参数为true时,默认为松散比较,导致弱类型,传入不同数据类型来绕过。示例: <?php $array=[1,2,3]; var_dump(in_array('aaa', $array)); //false var_dump(in_array('1aa', $array)); //true ?>
-
matriz_buscar()
该函数的作用是在数组中搜索某个键值,并返回键名 函数格式 array_search(要搜索的键值,被搜索的数组,设置TURE检查数据和数组值类型是否相同) 当数据类型不同会先把原有数据的数据类型的进行转换,导致弱类型的产生 示例: <?php $array=[1,2]; var_dump(array_search('aaa', $array)); //boolen false var_dump(array_search('2aa', $array)); //int 1 ?>
-
Otras funciones: intval(), is_numeric, strpos, etc. tienen problemas similares.
3. Lagunas históricas causadas por tipos débiles
- Vulnerabilidad de restablecimiento de contraseña de usuario arbitrario de DedeCMS
- Restablecimiento de contraseña de ZPanel
- Inyección secundaria PHPYun
- Inyección SQL de Piwigo
- Inyección HDwikiSQL
2. Análisis de las preguntas de muestra del CTF
1. Derivación MD5
Mira el código primero:
1 <?php
2 if (isset($_GET['Username']) && isset($_GET['password'])) {
3 $logined = true;
4 $Username = $_GET['Username'];
5 $password = $_GET['password'];
6
7 if (!ctype_alpha($Username)) {
$logined = false;} //usernam必须为字符型
8 if (!is_numeric($password) ) {
$logined = false;} //passwor必须为数值型
9 if (md5($Username) != md5($password)) {
$logined = false;}
10 if ($logined){
11 echo "successful";
12 }else{
13 echo "login failed!";
14 }
15 }
16 ?>
Se puede ver que aquí se debe pasar un parámetro variable de nombre de usuario y contraseña, y si el nombre de usuario no es igual a la contraseña, el valor md5 debe ser igual a omitir. Así que aquí necesitamos encontrar un par de colisiones Md5. Dado que aquí se usa "!=", puede encontrar el par de colisión cifrado que comienza con 0e para omitir.
Aquí se utiliza un par de colisión:
username= QNKCDZO
password= 240610708
Resultados de la prueba:
2, array_srach () puente
código fuente:
<?php
if(!is_array($_GET['test'])){
exit();}
$test=$_GET['test'];
for($i=0;$i<count($test);$i++){
if($test[$i]==="admin"){
//使用强比较判断数组中是否存在admin键值,如果存在,输出error。
echo "error";
exit();
}
$test[$i]=intval($test[$i]);
}
if(array_search("admin",$test)===0){
echo "flag";
}else{
echo "false";
}
?>
Análisis: Aquí necesitamos usar la característica de array_search() que la búsqueda de tipo débil cambiará el tipo de número.Dado que $test[$i]=intval($test[$i]);
los valores en la matriz se cambiarán a plástico, entonces en array_serch, el administrador se convertirá a plástico para comparar , y el administrador convertido es "0", por lo que debemos hacer que la matriz entrante no contenga administrador, y el primer valor se puede omitir después de convertirlo a "0" por intval. Aquí dejamos directamente que la matriz test[]=0 para pasar por alto O podemos omitirlo configurando el primero de la matriz en cualquier cadena que no comience con un número.
Resultados de la prueba:
3. Ejemplo: HDWIKI insípida inyección SQL
Código fuente del punto de vulnerabilidad:
function dofocus(){
$doctype = $this->get[2]; //通过GET方式获取doctype
switch($doctype){
case 2:
$type = 'hot';
$navtitle = $this->view->lang['hotDoc'];
break;
case 3:
$type = 'champion';
$navtitle = $this->view->lang['wonderDoc'];
break;
default: //如果 $doctype 不等于2或者3,则会进入默认程序,设置 $docty2=1,所以需要绕过switch检测,不进入默认程序。这里就可以利用switch弱类型绕过。
$doctype = 1;
$navtitle = $this->view->lang['focusDoc'];
$type = 'focus';
}
$url = 'list-focus-'.$doctype;
$this->get[3] = empty($this->get[3]) ? NULL : $this->get[3];
$page = max(1, intval($this->get[3]));
$start_limit = ($page - 1) * $this->setting['list_focus'];
$total=100;
$num=10;
$count=$this->db->fetch_total('focus',"type=$doctype"); //漏洞点,拼接了$doctype到sql语句中。
$count=($count<$total)?$count:$total;
$list=$_ENV['doc']->get_focus_list($start_limit,$this-> setting['list_focus'],$doctype);
$departstr=$this->multi($count, $this->setting['list_focus'], $page,$url);
$this->view->assign('navtitle',$navtitle);
$this->view->assign("departstr",$departstr);
$this->view->assign('type',$type);
$this->view->assign('list',$list);
//$this->view->display('list');
$_ENV['block']->view('list');
}
Entonces, podemos construir $doctype=2 o 1=1 para evitar la detección del interruptor, lo que provoca la inyección.