Although PHP is the best language in the world, there are also some security issues with weakly typed languages. WordPress has a history of security issues due to flaws in PHP itself, such asCVE-2014-0166Cookie forgery in PHP takes advantage of the weakness of PHP Hash comparisons. Of course, this situation is generally not used in actual combat, but it is a knowledge point worth investigating in CTF competition, hereby recorded and summarized.

First, precision bypass defects

The theory of

Floating-point calculations in PHP often produce values that are not the expected result, due to the limited accuracy of floating-point numbers. Although it depends on the system, PHP usually uses IEEE 754 double format, and the maximum relative error due to rounding is 1.11E-16. Non-basic mathematical operations may give larger errors and allow for error transfer when performing compound operations. Here’s an interesting example:

Rational numbers that can be expressed accurately in decimal notation, such as 0.1 or 0.7, no matter how many mantissa are represented accurately by the binary used internally, and therefore cannot be converted to the binary format without losing a bit of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) usually returns 7 instead of the expected 8, because the internal representation of the result is something like 7.99999999999991118… .

practice

Many write-ups on the Internet feel like writing write-up after reading the answers. I think the real write-up should reflect my own thinking in it.

Topic describes

Let’s pass 2017 to the server.

KaoChaDian

  • PHP floating point accuracy

write-up

what year is this? So the first reaction is to simply assign the year parameter to 2017:

? year=2017Copy the code

However, the results are as follows:



There are hints. InstructionsyearThis parameter is correct, but2017Cannot appear in7If you don’t know PHP precision, you are definitely right2017Various encoding bypasses are performed, but here the encoding is also filtered:



So the final possibility is to use PHP precision to get around it:

? Year = 2016.99999999999Copy the code

Second, the defects of type conversion

The theory of

PHP provides the is_numeric function, which is used to determine whether the variable is numeric. A feature of the weakly typed PHP language that when an integer is compared to a line of another type, the other type intVal is first digitized and then compared.

practice

Is_numeric () is used to determine whether there is a number, usually in conjunction with numeric values.

Case code

<? php error_reporting(0); $flag = 'flag{1S_numer1c_Not_S4fe}'; $id = $_GET['id']; is_numeric($id)? die("Sorry...." ):NULL; if($id>665){ echo $flag; }? >Copy the code

KaoChaDian

  • PHP type conversion defects

write-up

First check the value of the parameter ID submitted by GET. The ID is checked by the is_numeric function to determine whether it is a number or, if so, GG. If the value of id is greater than 665, flag is displayed. At first glance it may seem impossible, but if you know a feature of the weak-typed PHP language, when an integer is compared to a line of another type, the intVal of the other type is first digitized and then compared. This feature can be easily bypassed.

http://localhost/?id=666gg
Copy the code

3. Defects of loose comparators

The theory of

There are two types of PHP operators that compare equality, one strictly and the other loosely.

If you compare a number to a string or compare strings that involve numeric content, the string is converted to a numeric value and the comparison is performed as a numeric value



Strict comparatorA strict comparator determines whether two string types are equal before comparing.

=== // congruent! == // not congruentCopy the code

Loose comparator A loose comparator converts the string type to the same before comparing.

== // =! = / /Copy the code



PHP automatically converts a variable to the correct data type based on its value. This is very different from languages like C and C++ and Java. While PHP is convenient for programmers, it comes with some security issues.

A simple example

<? php $a = null; $b = false; echo $a==$b; echo "<br>"; $c = ""; $d = 0; echo $c==$d ? >Copy the code

Due to the automatic conversion of variables in PHP, here

$a==$b and $c==$dCopy the code

So the output of the page is:

An in-depth example

The following explanation will be easier to understand with PHP equality comparison defects:

var_dump(0=="gg");  //true
var_dump(0==="gg"); //false
var_dump(1=="gg");  //false
Copy the code

A loose comparison between 0 and gg will convert gg to a numeric value, forcing the conversion. Since gg is a string, the conversion result is 0, so the output is true

Gg is a string and is not equal to 0, so false is printed

A loose comparison between 0 and gg will convert gg to a numeric value and force conversion. Since gg is a string, the converted result is 0, which is not equal to 1, so false is printed

var_dump(1=="1gg"); //true 
var_dump(1=="gg1"); //false
Copy the code

1 is loosely compared with 1gg. When 1gg is cast to an int, the first digit of the string is 1, so 1gg is cast to 1, so the output is true

A strict comparison of 1 to gg1, the first digit of the string gg1 is not a number, so it is cast to 0, so false is printed

var_dump("0e123" == "0e456");  //true
var_dump("0e123" == "0eabc");  //flase
Copy the code

In this case, there is an 0e in the string, as described in the PHP manual:

When a string is evaluated as a value, the result and type are as follows: If the string doesn't contain '.','e', or 'e' and the value is within the integer range, the string is evaluated as an int. In all other cases, the string is evaluated as float. If the string starts with a valid value, it is used, otherwise it is 0.Copy the code

When 0E123 and 0E456 are not strictly compared with each other, the string 0e will be recognized as the number of science and technology method. No matter how many power of 0 is zero, so it is equal, and the output is true

When comparing 0e123 with 0eABC, the string 0e should be recognized as a scientific and technical number, but the string 0e is followed by ABC. The scientific index in mathematics cannot contain letters. So although the string starts with 0e, the following ABC does not conform to the specification of scientific technique, so the output is false

practice

Md5 Skirt (Hash comparison defects) Is a classic MD5 Collision problem in the Network Attack and Defense Training platform of Nanjing University of Posts and Telecommunications. There are many WriteUp articles about this topic on the Internet, but there are few in-depth analysis about it

Topic describes

Md5 collision source

<? php $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"; }? >Copy the code

KaoChaDian

  • Simple PHP code audit
  • PHP weak type Hash comparison defect

write-up

From the source can input a parameter of the variable, a first is not equal to QNKCDZO and the MD5 value of a must be equal to QNKCDZO encrypted MD5 value. At first glance like there can be no such value, but here QNKCDZO encrypted md5 value is 0 e830400451993494058024219903391 here is 0 e at the beginning, when compare equal, PHP as scientific notation, 0 no matter how much power is zero. So here use the weakness of the weak type comparison above to solve the problem:? a=s155964671a

After the string is encryptedmd5A list of strings of 0exxxx (x must be a base 10 number)

string md5
QNKCDZO 0e830400451993494058024219903391
240610708 0e462097431906509019562988736854
aabg7XSs 0e087386482136013740957780965295
aabC9RqS 0e041022518165728065344349536299
s878926199a 0e545993274517709034328855841020

4. Sha1 () MD5 () encryption function vulnerability

The theory of

Md5 () and SHA1 () encrypting an array returns NULL

practice

Boston Key Party CTF 2015: Prudential

Topic describes

I dont think sha1 isbroken.Prove me wrong.

The question gives a login box:

KaoChaDian

  • Sha1 () function vulnerability defect

write-up

The source code is given as follows:

<html> <head> <title>level1</title> <link rel='stylesheet' href='style.css' type='text/css'> </head> <body> <? php require 'flag.php'; if (isset($_GET['name']) and isset($_GET['password'])) { if ($_GET['name'] == $_GET['password']) print 'Your password can not be your name.'; else if (sha1($_GET['name']) === sha1($_GET['password'])) die('Flag: '.$flag); else print '<p class="alert">Invalid password.</p>'; }? > <section class="login"> <div class="title"> <a href="./index.txt">Level 1</a> </div> <form method="get"> <input type="text" required name="name" placeholder="Name"/><br/> <input type="text" required name="password" placeholder="Password" /><br/> <input type="submit"/> </form> </section> </body> </html>Copy the code

Analyze the core login code as follows:

if ($_GET['name'] == $_GET['password'])
    print 'Your password can not be your name.';
else if (sha1($_GET['name']) === sha1($_GET['password']))
    die('Flag: '.$flag);
Copy the code

GET submits two fields: name and password.

  • name ! = password
  • sha1(name) == sha1(password)

This may seem impossible at first glance, but the sha1() function will return NULL when it cannot handle an array, so it can bypass the verification of the if statement. If the condition is true, it will get a flag. Construct statement as follows:

? name[]=a&password[]=b

There are two criteria for getting a flag:

  • A is not equal to B
  • Both name and password are returned after sha1() because they are arraysNULL

Get flag I_think_that_I_just_broke_sha1

Expand the summary

Sha1 () does not handle arrays. Md5 () does not handle arrays.

<? php error_reporting(0); $flag = 'flag{I_think_that_I_just_broke_md5}'; 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']) === sha1($_GET['password'])) die($flag); else print 'Invalid password'; }? >Copy the code

The core code is as follows:

If ($_GET [' username '] = = $_GET [' password ']) and must meet: if (md5 ($_GET [' username ']) = = = sha1 ($_GET [' password ']))Copy the code

The md5() function can’t handle the array.

? username[]=a&password[]=b

5. String processing function vulnerabilities

The theory of

  • strcmp()Function: Compares two strings (case sensitive).

Usage:

int strcmp ( string $str1 , string $str2 )
Copy the code

The specific usage is explained as follows:

Parameter 'str1' first string. Argument 'str2' second string. Return '< 0' if str1 is less than str2; Return '> 0' if 'str1' is greater than 'str2'; If they are equal, return 0.Copy the code

The function receives a nonconforming type, such as an array type, and an error occurs. However, in PHP prior to 5.3, an error warning message was displayed and the return 0!!!! was returned So even though it’s wrong, it’s equal.

  • ereg()Function: string regular match.
  • strpos()Function: finds the position of the first occurrence of a string in another string, case sensitive.

Both functions are used to process strings, but both return NULL when an array argument is passed in.

practice

Boston Key Party CTF 2015: Northeastern Univ

Topic describes

Of course, a timing attack might be the answer, but Im quite sure that you can do better than that. The question gives a login box:

KaoChaDian

  • String handling function vulnerability vulnerability

write-up

The source code is given as follows:

<html> <head> <title>level3</title> <link rel='stylesheet' href='style.css' type='text/css'> </head> <body> <? php require 'flag.php'; if (isset($_GET['password'])) { if (strcmp($_GET['password'], $flag) == 0) die('Flag: '.$flag); else print '<p class="alert">Invalid password.</p>'; }? > <section class="login"> <div class="title"> <a href="./index.txt">Level 3</a> </div> <form method="get"> <input type="text" required name="password" placeholder="Password" /><br/> <input type="submit"/> </form> </section> </body> </html>Copy the code

Analyze the core login code as follows:

if (strcmp($_GET['password'], $flag) == 0)
Copy the code

Here we use= =Loosely compared$flagAnd those submitted by GETpasswordIf you want to wait, get the flag. I’m going to use theta= =An error will be reported when using strings to process arrays in a looser nature comparison5.3After displaying an error warning message in PHP, thereturn 0. So this is going to bepasswordParameter specified as an array, using a function vulnerability to getflag:

Expand the summary

In addition to STRCMP (), the ereg() and strpos() functions also return NULL when handling arrays. The test code is as follows:

<? php error_reporting(0); $flag = 'flag{P@ssw0rd_1s_n0t_s4fe_By_d0uble_Equ4ls}'; 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); else echo 'Invalid password'; }? >Copy the code

Pass in an array assigned to the password argument:

http://localhost/?password[]=gg
Copy the code

Ereg () functionIs a string that is passed in to an array and returnedNULL.NULLandFALSE, is not identical (===), satisfying the first oneifConditions; whileThe strpos () functionIt also handles strings, and returns when passed an arrayNULL,NULL! ==FALSE, meet the conditions, get the flag:

Parse_str function variable override defect

The theory of

The parse_str function parses a string and registers it as a variable. It does not verify the existence of the current variable before registering it, so it overwrites the existing variable.

void parse_str ( string $str [, array &$arr ] )
Copy the code

STR is the string entered. Arr If a second variable arr is set, the variable will be stored as an array element instead.

practice

Test code:

<? php error_reporting(0); $flag = 'flag{V4ri4ble_M4y_Be_C0verEd}'; if (empty($_GET['b'])) { show_source(__FILE__); die(); }else{ $a = "www.sqlsec.com"; $b = $_GET['b']; @parse_str($b); if ($a[0] ! = 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')) { echo $flag; }else{ exit('your answer is wrong~'); }}? >Copy the code

KaoChaDian

  • Parse_str variable overwrite defect

write-up

Find the core code:

@parse_str($b); $a[0]! $a[0]! $a[0]) == md5('QNKCDZO' && md5('QNKCDZO')Copy the code

$a[0]; $a[0]; $a[0]; $a[0];

$a = "www.sqlsec.com";
Copy the code

This is actually the address of my blog ~~ but it doesn’t matter. The whole code seems impossible at first glance, but it is possible to reassign the variable of A by taking advantage of the flaw in the variable override function. The following if statement is bypassed by the md5() comparison flaw mentioned earlier in this article:

http://localhost/?b=a[0]=240610708
Copy the code

reference

  • The PHP comparison operator
  • PHP Float indicates the Float type
  • PHP type comparison table
  • Summary of weak typing in PHP
  • The PHP Hash comparison has defects, affecting a large number of key services, such as login authentication and password forgetting
  • PHP code auditing (basic code auditing and CTF)
  • A brief discussion on WEAK type security in PHP
  • NJCTF2017 Online Contest Web problem solving
  • CTF’s summary of PHP Dark Magic
  • Some features of PHP in CTF
  • PHP floating point arithmetic precision problem
  • PHP STRCMP ()
  • Dangerous is_NUMERIC — PHPYun 2015-06-26 Secondary injection vulnerability analysis
  • [Code audit] Detailed explanation of variable coverage vulnerability

* Article by Guo Guang, FreeBuf.COM