Automatisierte Sicherheitsanalyse von Webapplikationen
Static Code Analysis
- f Complex PHP Application Vulnerabilities
Static Code Analysis
- f Complex PHP Application Vulnerabilities
Johannes Dahse
Static Code Analysis of Complex PHP Application Vulnerabilities - - PowerPoint PPT Presentation
Static Code Analysis Automatisierte Sicherheitsanalyse of Complex PHP Application Vulnerabilities von Webapplikationen Static Code Analysis of Complex PHP Application Vulnerabilities Johannes Dahse Static Code Analysis Automatisierte
Johannes Dahse
3
4
5
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 1000 2000 3000 4000 5000 6000 7000 8000 Other PHP JS Python Perl Ruby CFM Java ASP PHP 10 20 30 40 50 60 70 80 90
Source: W3Techs Source: MITRE CVE
6
Callgraph for Wordpress Index Page
7
Static analyze code without execution Dynamic analyze code while execution Code Coverage full Single execution path Data Coverage Compile-time data Runtime data (valid for environment) Decidability Halting Problem Real data
8
9
10
1 $cookie = $_COOKIE['text'];
$cookie = $_COOKIE['text'];
Variable Variable String
$cookie
Assign
$_COOKIE
var expr
'text'
dim variable array string
11
12
13
14
15
16
17
Code AST CFG Basic Blocks Report
18
Code AST CFG Basic Blocks Report
19
Code AST CFG Basic Blocks Report
source sink
20
Code AST CFG Basic Blocks Report
forwards-directed object analysis
21
Code AST CFG Basic Blocks Report
forwards-directed object analysis
Software KLOC Drupal 933 Magento 909 Typo3 646 Joomla 444
Wordpress
282
22
Code AST CFG Basic Blocks Report
forwards-directed object analysis
23
24
✗ Authorization Bypass ✗ Cross-Site Request Forgery ✔ Cross-Site Scripting ✔ Code Execution ✔ Command Execution ✔ Connection String Injection ✔ Denial of Service ✔ Directory Listing ✔ Execution After Redirect ✔ File Delete ✔ File Disclosure ✔ File Inclusion ✔ File Overwrite ✔ File System Manipulation ✔ File Upload ✔ HTTP Response Splitting ✔ Information Leakage ✔ LDAP Injection ✔ Log Forgery ✔ Mass Assignment ✔ Memcached Injection ✔ Open Redirect ✔ PHP Object Injection ✔ Reflection/Autoload Injection ✗ Resource Contention ✔ Server-Side JavaScript Injection ✔ Server-Side Request Forgery ✔ Session Fixation ✔ SQL Injection ✔ Variable Manipulation ✗ Weak Cryptography ✔ XML/XXE Injection ✔ XPath Injection
25
1 $url = htmlentities($_GET['id']); “ → " 2 echo '<a href=““>' . $url . '</a>'; < → < 3 echo “<a href='$url'>click</a>“; 4 echo '<a href=“' . $url . '“>click</a>';
source sensitive sink sanitization
5 $id = mysql_real_escape_string($_GET['id']); ' → \' 6 mysql_query(“SELECT * FROM t WHERE id = '$id'“); 7 mysql_query('SELECT * FROM t WHERE id = ' . $id);
26
1 $url = htmlentities($_GET['id']); “ → " 2 echo '<a href=““>' . $url . '</a>'; < → < 3 echo “<a href='$url'>click</a>“; 'onclick='alert(1) 4 echo '<a href=“' . $url . '“>click</a>';
source sensitive sink sanitization
javascript:alert(1)
5 $id = mysql_real_escape_string($_GET['id']); ' → \' 6 mysql_query(“SELECT * FROM t WHERE id = '$id'“); 7 mysql_query('SELECT * FROM t WHERE id = ' . $id);
1 or 1=1
27
$_GET $_POST $_COOKIE $_REQUEST $_FILES $_SERVER ... print() mysql_query() include() eval() system() ... XSS SQL Injection File Inclusion Code Execution Command Execution ...
= user input sensitive sink +
28
$_GET $_POST $_COOKIE $_REQUEST $_FILES $_SERVER ... print() mysql_query() include() eval() system() ... XSS SQL Injection File Inclusion Code Exec Cmd Exec ...
= user input sensitive sink
htmlentities() addslashes() basename() (int) escapeshellarg() ...
sanitization + +
29
$_GET $_POST $_COOKIE $_REQUEST $_FILES $_SERVER ... print() mysql_query() include() eval() system() ... XSS SQL Injection File Inclusion Code Exec Cmd Exec ...
= user input sensitive sink
HTML SQL File Path PHP OS Command ...
markup
htmlentities() addslashes() basename() (int) escapeshellarg() ...
sanitization + + +
30
1 $id = $_POST['id']; 2 if(...) { 3 $id = (int)$id; 4 } 5 else { 6 $id = htmlentities($id); 7 } 8 echo "<div id='$id'>";
31
1 $id = $_POST['id']; 2 if(...) { 3 $id = (int)$id; 4 } 5 else { 6 $id = htmlentities($id); 7 } 8 echo "<div id='$id'>";
echo "<div id='$id'>"; $id = htmlentities($id); $id = (int)$id; $id = $_POST['id'];
32
echo "<div id='$id'>";
Markup Context $id: HTML attribute single-quoted (SQ)
$id = (int)$id; $id = htmlentities($id); $id = $_POST['id'];
33
echo "<div id='$id'>"; $id = $_POST['id']; $id = (int)$id; $id = htmlentities($id);
Markup Context $id: HTML attribute single-quoted (SQ)
$id
34
echo "<div id='$id'>"; $id = $_POST['id']; $id = (int)$id; $id = htmlentities($id);
Markup Context $id: HTML attribute single-quoted (SQ)
$id
Sanitized: Integer only
35
echo "<div id='$id'>"; $id = $_POST['id']; $id = (int)$id; $id = htmlentities($id);
Markup Context $id: HTML attribute single-quoted (SQ)
$id
Sanitizes: " < >
XSS DQ" Attribute XSS <> Element
36
echo "<div id='$id'>"; $id = $_POST['id']; $id = (int)$id; $id = htmlentities($id);
Markup Context $id: HTML attribute single-quoted (SQ)
$id
User input (no " < >)
XSS DQ" Attribute
id
XSS <> Element
37
echo "<div id='$id'>"; $id = $_POST['id']; $id = (int)$id; $id = htmlentities($id);
Markup Context $id: HTML attribute single-quoted (SQ)
$id
User input (no " < >)
XSS DQ" Attribute
id
XSS <> Element
Vulnerable!
38
3 21 16 20 5 24 2 25 1 17 23 13 7 8 14 18 22 15 10 19 9 11 4 6 12 50000 100000 150000 200000 250000 300000 350000
3 21 16 20 5 24 2 25 1 17 23 13 7 8 14 18 22 15 10 19 9 11 4 6 12 500 1000 1500 2000 2500 3000 3500
39
DQ Element SQ
1000 2000 3000 4000 5000 6000 7000 8000 9000 10000
Replace Regex Validate Explicit Typecast Comparing Type Validation Converting Other
Element DQ SQ
20 40 60 80 100 120 140 160 180
Converting Comparing Regex Replace Escaping Regex Validate Replace Other 52% 41% 5%
40
SQ NQ DQ
1000 2000 3000 4000 5000 6000
Prepare Replace Regex Validate Comparing Type Validation Escape Explicit Typecast Other
NQ SQ DQ
20 40 60 80 100 120 140 160 180 200
Regex Replace Prepare Truncate Comparing Replace Regex Validate Escaping Other 67% 31% 2%
41
25 Applications, 2.5 MLOC, 26K Dataflows
42
25 Applications, 2.5 MLOC, 26K Dataflows
43
44
45
write read
database application
user input
database
write
application
user input
!“*$()&/'\ !“*$()&/'\
read
46
...
...
... User input Persistent Data Store (PDS) Sensitive Sink 1. 2.
47
1 $name = $_POST['name']; 2 if(...) { 3 $role = 'admin'; 4 } 5 else { 6 $role = 'user'; 7 } 8 mysql_query("INSERT INTO users VALUES('$name', '$role')");
48
1 $name = $_POST['name']; 2 if(...) { 3 $role = 'admin'; 4 } 5 else { 6 $role = 'user'; 7 } 8 mysql_query("INSERT INTO users VALUES('$name', '$role')");
mysql_query("INSERT INTO users VALUES('$name', '$role')"); $role = 'admin'; $role = 'user'; $name = $_POST['name'];
49
1 $name = $_POST['name']; 2 if(...) { 3 $role = 'admin'; 4 } 5 else { 6 $role = 'user'; 7 } 8 mysql_query("INSERT INTO users VALUES('$name', '$role')");
mysql_query("INSERT INTO users VALUES('$name', '$role')"); $role = 'admin'; $role = 'user'; $name = $_POST['name'];
50
1 $name = $_POST['name']; 2 if(...) { 3 $role = 'admin'; 4 } 5 else { 6 $role = 'user'; 7 } 8 mysql_query("INSERT INTO users VALUES('$name', '$role')");
mysql_query("INSERT INTO users VALUES('$name', '$role')"); $role = 'admin'; $role = 'user'; $name = $_POST['name'];
51
1 $name = $_POST['name']; 2 if(...) { 3 $role = 'admin'; 4 } 5 else { 6 $role = 'user'; 7 } 8 mysql_query("INSERT INTO users VALUES('$name', '$role')");
mysql_query("INSERT INTO users VALUES('$name', '$role')"); $role = 'admin'; $role = 'user'; $name = $_POST['name'];
SQLi
POST[name]
52
1 $name = addslashes($_POST['name']); 2 if(...) { 3 $role = 'admin'; 4 } 5 else { 6 $role = 'user'; 7 } 8 mysql_query("INSERT INTO users VALUES('$name', '$role')");
53
1 $name = addslashes($_POST['name']); 2 if(...) { 3 $role = 'admin'; 4 } 5 else { 6 $role = 'user'; 7 } 8 mysql_query("INSERT INTO users VALUES('$name', '$role')");
mysql_query("INSERT INTO users VALUES('$name', '$role')"); $role = 'admin'; $role = 'user'; $name = addslashes($_POST['name']); INSERT INTO users VALUES('$_POST[name]', 'admin') INSERT INTO users VALUES('$_POST[name]', 'user')
54
1 $name = addslashes($_POST['name']); 2 if(...) { 3 $role = 'admin'; 4 } 5 else { 6 $role = 'user'; 7 } 8 mysql_query("INSERT INTO users VALUES('$name', '$role')");
mysql_query("INSERT INTO users VALUES('$name', '$role')"); $role = 'admin'; $role = 'user'; $name = addslashes($_POST['name']); INSERT INTO users VALUES('$_POST[name]', 'admin') INSERT INTO users VALUES('$_POST[name]', 'user')
name role
users
55
1 $name = $_POST['name']; 2 if(...) { 3 $role = 'admin'; 4 } 5 else { 6 $role = 'user'; 7 } 8 mysql_query("INSERT INTO users VALUES('$name', '$role')");
mysql_query("INSERT INTO users VALUES('$name', '$role')"); $role = 'admin'; $role = 'user'; $name = $_POST['name']; INSERT INTO users VALUES('$_POST[name]', 'admin') INSERT INTO users VALUES('$_POST[name]', 'user')
SQLi
POST[name] users
name role
56
1 $r = mysql_query( 'SELECT name FROM users'); 2 if(...) { 3 $row = mysql_fetch_assoc($r); 4 } 5 else { 6 die('error'); 7 } 8 echo "Hi " . $row['name'];
57
1 $r = mysql_query( 'SELECT name FROM users'); 2 if(...) { 3 $row = mysql_fetch_assoc($r); 4 } 5 else { 6 die('error'); 7 } 8 echo "Hi " . $row['name'];
echo "Hi " . $row['name']; $row = mysql_fetch_assoc($r); $r = mysql_query( 'SELECT name FROM users');
Temp XSS
users[name]
58
PDS *
Temp XSS users[name]
id name pass
PDS'
users
59
PDS *
Temp XSS users[name]
id name pass
PDS'
users
tainted?
60
PDS *
Temp XSS users[name]
id name pass
PDS'
users
sanitized?
61
PDS *
id name pass
PDS'
users
Second-Order XSS $_POST[name]
Temp XSS users[name]
62
63
/data/papers/1.pdf
OC_headerFile
SQLi or XSS
Remote Code Execution
All issues are fixed in version 5.31 and 6.01
File Upload Second-Order LFI
64
65
66
67
class Text { public function __construct($data) { $this->data = $data; } } $object1 = new Text('Syssec'); $tmp = serialize($object1); // O:4:"Text":1:{s:4:"data";s:6:"Syssec";} $object2 = unserialize($tmp); echo $object2->data;
68
class Text { public function __construct($data) { $this->data = $data; } } $object1 = new Text('Syssec'); setcookie('tmp', serialize($object1)); // O:4:"Text":1:{s:4:"data";s:6:"Syssec";} $object2 = unserialize($_COOKIE['tmp']); echo $object2->data;
69
class Text { public function __construct($data) { $this->data = $data; } } $object1 = new Text('Syssec'); setcookie('tmp', serialize($object1)); // O:4:"Text":1:{s:4:"data";s:6:"Syssec";} // O:8:"stdClass":1:{s:4:"data";s:3:"NDS";} $object2 = unserialize($_COOKIE['tmp']); echo $object2->data;
70
class Text { public function __construct($d){ $this->data = $d; } } // O:4:"Text":1:{s:4:"data";s:6:"Syssec";} // O:4:"File":1:{s:8:"filename";s:10:"config.php";} $object2 = unserialize($_COOKIE['tmp']); echo $object2->data; class File { public function __destruct(){ unlink($this->filename); } }
71
class File { public function __destruct(){ $this->handler->close(); } } // O:4:"File":1:{s:7:"handler";O:3:"ABC":0:{};} $object2 = unserialize($_COOKIE['tmp']); echo $object2->data;
72
class File { public function __destruct(){ $this->handler->close(); } } // O:4:"File":1:{s:7:"handler";O:7:"Process":0:{};} $object2 = unserialize($_COOKIE['tmp']); echo $object2->data; class Process { public function close() { system('kill '.$this->pid); } } Process
73
class File { public function __destruct(){ $this->handler->close(); } } // O:4:"File":1:{s:7:"handler";O:7:"Process":0:{};} $object2 = unserialize($_COOKIE['tmp']); echo $object2->data; class Process { public function close() { system('kill '.$this->pid); } } Process
74
75
class File { public function __destruct(){ $this->handler->close(); } } // O:4:"File":1:{s:7:"handler";O:7:"Process":1: {s:3:"pid";s:6:"0;calc";};} $object2 = unserialize($_COOKIE['tmp']); echo $object2->data; class Process { public function close() { system('kill '.$this->pid); } } >kill 0;calc
76
class File { public function __destruct(){ $this->handler->close(); } } // O:4:"File":1:{s:7:"handler";O:7:"Process":1: {s:3:"pid";s:6:"0;calc";};} $object2 = unserialize($_COOKIE['tmp']); echo $object2->data; class Process { public function close() { system('kill '.$this->pid); } } >kill 0;calc
77
$tmp = $_COOKIE['tmp']; $obj = unserialize($tmp);
78
$tmp = $_COOKIE['tmp']; $obj = unserialize($tmp);
79
$tmp = $_COOKIE['tmp']; $obj = unserialize($tmp);
80
$tmp = $_COOKIE['tmp']; $obj = unserialize($tmp); $obj
81
$tmp = $_COOKIE['tmp']; $obj = unserialize($tmp); $obj echo $obj->data;
82
class File { public function __destruct(){ $this->handler->close(); } } class Process { public function close() { system('kill '.$this->pid); } } class Database { public function close() { mysql_close($this->db); } }
83
class File { public function __destruct(){ $this->handler->close(); } } class Process { public function close() { system('kill '.$this->pid); } } class Database { public function close() { mysql_close($this->db); } }
84
class File { public function __destruct(){ $this->handler->close(); } } class Process { public function close() { system('kill '.$this->pid); } } class Database { public function close() { mysql_close($this->db); } }
$this->pid
85
class File { public function __destruct(){ $this->handler->close(); } } class Process { public function close() { system('kill '.$this->pid); } } class Database { public function close() { mysql_close($this->db); } }
$this->pid $this->handler->pid
86
$tmp = $_COOKIE['tmp']; $obj = unserialize($tmp); $obj->handler->pid
$this->handler->pid
87
$tmp = $_COOKIE['tmp']; $obj = unserialize($tmp); $obj->handler->pid
$this->handler->pid
88
89