PCスペック

備忘録。

マザーボード ASUS PRIME Z390-A (Intel Z390 搭載 LGA1151 対応) ¥ 21,999
CPU Intel Core i5 9600 ¥ 26,921
GPU ASUS TURBO-RTX2070S-8G-EVO (ストレート排気モデル) ¥ 68,147
メモリ Crucial by Micron W4U2666CM-16G (PC4-21300(DDR4-2666) 16GB×2枚 288pin) ¥ 13,442
SSD Western Digital WD Blue WDS250G2B0A (SATA 3.0(SATA 6Gb/s)) * 2 @¥ 4,867
Blu-ray I-O DATA BRD-S16PX ¥ 10,064
電源 Corsair HX1000i 80PLUS PLATINUM 1000W ¥ 18,118
OS Windows10 Pro 64bit (DSP版) ¥ 20,477
ケース Fractal Design Define R6 Blackout ¥ 13,606
合計 ¥ 202,508

2019/12-2020/1ごろにAmazonで調達。

WSL2でCUDAを使う

備忘録

参考:
qiita.com

やったこと

  • TPMを有効化 (BIOSで、Discrete TPM -> Firmware TPMに変更)
  • Windows 11 (Insider Preview)にアップグレード
  • 最新のドライバインストール
  • Ubuntu (20.04)にcuda-toolkit-11-4 のインストール

この時点で、こんな感じのエラーが出た。

$ ./deviceQuery
./deviceQuery Starting…

CUDA Device Query (Runtime API) version (CUDART static linking)

cudaGetDeviceCount returned 35
-> CUDA driver version is insufficient for CUDA runtime version
Result = FAIL

調べてみてもよくわからなかったが、

  • cudaのアップグレード
  • (ホスト)Windowsの再起動

をしたら直った。

$ ./deviceQuery
./deviceQuery Starting...

 CUDA Device Query (Runtime API) version (CUDART static linking)

Detected 1 CUDA Capable device(s)

Device 0: "NVIDIA GeForce RTX 2070 SUPER"
  CUDA Driver Version / Runtime Version          11.4 / 11.4
  CUDA Capability Major/Minor version number:    7.5
  Total amount of global memory:                 8192 MBytes (8589934592 bytes)
  (040) Multiprocessors, (064) CUDA Cores/MP:    2560 CUDA Cores
  GPU Max Clock rate:                            1770 MHz (1.77 GHz)
  Memory Clock rate:                             7001 Mhz
  Memory Bus Width:                              256-bit
  L2 Cache Size:                                 4194304 bytes
  Maximum Texture Dimension Size (x,y,z)         1D=(131072), 2D=(131072, 65536), 3D=(16384, 16384, 16384)
  Maximum Layered 1D Texture Size, (num) layers  1D=(32768), 2048 layers
  Maximum Layered 2D Texture Size, (num) layers  2D=(32768, 32768), 2048 layers
  Total amount of constant memory:               65536 bytes
  Total amount of shared memory per block:       49152 bytes
  Total shared memory per multiprocessor:        65536 bytes
  Total number of registers available per block: 65536
  Warp size:                                     32
  Maximum number of threads per multiprocessor:  1024
  Maximum number of threads per block:           1024
  Max dimension size of a thread block (x,y,z): (1024, 1024, 64)
  Max dimension size of a grid size    (x,y,z): (2147483647, 65535, 65535)
  Maximum memory pitch:                          2147483647 bytes
  Texture alignment:                             512 bytes
  Concurrent copy and kernel execution:          Yes with 2 copy engine(s)
  Run time limit on kernels:                     Yes
  Integrated GPU sharing Host Memory:            No
  Support host page-locked memory mapping:       Yes
  Alignment requirement for Surfaces:            Yes
  Device has ECC support:                        Disabled
  Device supports Unified Addressing (UVA):      Yes
  Device supports Managed Memory:                Yes
  Device supports Compute Preemption:            Yes
  Supports Cooperative Kernel Launch:            Yes
  Supports MultiDevice Co-op Kernel Launch:      No
  Device PCI Domain ID / Bus ID / location ID:   0 / 2 / 0
  Compute Mode:
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 11.4, CUDA Runtime Version = 11.4, NumDevs = 1
Result = PASS

picoCTF 2021 Crypto (5) Mini RSA

Mini RSA
| 70 points
Tags:
AUTHOR: SARA

Description
What happens if you have a small exponent? There is a twist though, we padded the plaintext so that (M ** e) is just barely larger than N. Let's decrypt this: ciphertext

# cat ciphertext 
N: 1615765684321463054078226051959887884233678317734892901740763321135213636796075462401950274602405095138589898087428337758445013281488966866073355710771864671726991918706558071231266976427184673800225254531695928541272546385146495736420261815693810544589811104967829354461491178200126099661909654163542661541699404839644035177445092988952614918424317082380174383819025585076206641993479326576180793544321194357018916215113009742654408597083724508169216182008449693917227497813165444372201517541788989925461711067825681947947471001390843774746442699739386923285801022685451221261010798837646928092277556198145662924691803032880040492762442561497760689933601781401617086600593482127465655390841361154025890679757514060456103104199255917164678161972735858939464790960448345988941481499050248673128656508055285037090026439683847266536283160142071643015434813473463469733112182328678706702116054036618277506997666534567846763938692335069955755244438415377933440029498378955355877502743215305768814857864433151287
e: 3

ciphertext (c): 1220012318588871886132524757898884422174534558055593713309088304910273991073554732659977133980685370899257850121970812405700793710546674062154237544840177616746805668666317481140872605653768484867292138139949076102907399831998827567645230986345455915692863094364797526497302082734955903755050638155202890599808154558034707767377524500302754459807923331810585173010977657982069888996945830789092526932364658459034145456505057469113036134559745659079236466119515004648189278227777550415021840140147319061470183840214034417917161940379351273394212022847037696265532968684592354941479799473941357715953204487236888712642494877545201005807776354854390358015733495331101077851132489983665939643188064986446883595239842621440918456201787168234988410659153219277329426230136499096098072681939491840913961290536851217677043565743644469862992310241563891464225935615676242084658617931225618537173689559419607688905143683603007487996422560430269750305079282818976557285786253025774883158125978164878245223052992502106

e=3なので、3乗根を取ればいいはず。
 c \equiv m ^ e (mod  \ n)
 m \equiv c ^{1/e} (mod \ n)

>>> from gmpy2 import *
>>> c = 1220012318588871886132524757898884422174534558055593713309088304910273991073554732659977133980685370899257850121970812405700793710546674062154237544840177616746805668666317481140872605653768484867292138139949076102907399831998827567645230986345455915692863094364797526497302082734955903755050638155202890599808154558034707767377524500302754459807923331810585173010977657982069888996945830789092526932364658459034145456505057469113036134559745659079236466119515004648189278227777550415021840140147319061470183840214034417917161940379351273394212022847037696265532968684592354941479799473941357715953204487236888712642494877545201005807776354854390358015733495331101077851132489983665939643188064986446883595239842621440918456201787168234988410659153219277329426230136499096098072681939491840913961290536851217677043565743644469862992310241563891464225935615676242084658617931225618537173689559419607688905143683603007487996422560430269750305079282818976557285786253025774883158125978164878245223052992502106
>>> n = 1615765684321463054078226051959887884233678317734892901740763321135213636796075462401950274602405095138589898087428337758445013281488966866073355710771864671726991918706558071231266976427184673800225254531695928541272546385146495736420261815693810544589811104967829354461491178200126099661909654163542661541699404839644035177445092988952614918424317082380174383819025585076206641993479326576180793544321194357018916215113009742654408597083724508169216182008449693917227497813165444372201517541788989925461711067825681947947471001390843774746442699739386923285801022685451221261010798837646928092277556198145662924691803032880040492762442561497760689933601781401617086600593482127465655390841361154025890679757514060456103104199255917164678161972735858939464790960448345988941481499050248673128656508055285037090026439683847266536283160142071643015434813473463469733112182328678706702116054036618277506997666534567846763938692335069955755244438415377933440029498378955355877502743215305768814857864433151287
>>> cbrt(c)
mpfr('1.0685333265243248e+335')
>>> hex(int(cbrt(c)))
'0x1ebab45fa208b60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
>>> get_context().precision = 10000
>>> hex(int(cbrt(c)))
'0x1ebab45fa208b5e935ab142514c5ed26a3adfa2d78a734b1de5bf560ecd1e2164321f6a9ced9dd66e9607c02cd04f27c7c12b5a5ebf6c6e3980cd11999628f7d18bcbbf27d5f3c31b9a21bb9db47fdbdecf550feefd23486c3664e0e359c92c8b68d38e5a57be5190f9256fa51680bd79d1365836f0ce1efacfed4ede2ade5c5f0aa52741fbce11f4967b7d'
>>> int(cbrt(c)) ** 3 == n
False

単純に3乗根を取ってもダメ見たい。
 c \equiv m ^ e (mod  \ n)
 c = m  ^{e} + k \cdot n
 c - k \cdot n = m ^{e}
 m = (c - k \cdot n)^{1/e}
なので、gmpy2.iroot()を使って、正しい値が取れるまでループさせる。

iroot(...)
iroot(x,n) returns a 2-element tuple (y, b) such that y is the integer n-th root of x and b is True if the root is exact. x must be >= 0 and n must be > 0.

Multiple-precision Integers — gmpy2 2.1.0a1 documentation

※iroot(x, n)は x >= 0じゃないといけないので、kの符号を反転させる。

>>> while True:
...   m, b = iroot(c + k * n, 3)
...   if b == True:
...     break
...   k += 1
... 
>>> k
3533
>>> m
mpz(1787330808968142828287809319332701517353332911736848279839502759158602467824780424488141955644417387373185756944952906538004355347478978500948630620749868180414755933760446136287315896825929319145984883756667607031853695069891380871892213007874933611243319812691520078269033745367443951846845107464675742664639073700704505958478225302653)
>>> from Crypto.Util.number import long_to_bytes
>>> long_to_bytes(m)
b'                                                                                                        picoCTF{e_sh0u1d_b3_lArg3r_aef7377d}'
>>> 

" e should be larger"

picoCTF 2021 General Skills

Obedient Cat

Description
This file has a flag in plain sight (aka "in-the-clear"). Download flag.

# cat flag 
picoCTF{s4n1ty_v3r1f13d_f28ac910}

"sanity verified"

Python Wrangling

Description
Python scripts are invoked kind of like programs in the Terminal... Can you run this Python script using this password to get the flag?

# wget https://mercury.picoctf.net/static/0bf545252b5120845e3b568b9ad0277e/ende.py
/// skipped ///
# wget https://mercury.picoctf.net/static/0bf545252b5120845e3b568b9ad0277e/pw.txt
/// skipped ///
# wget https://mercury.picoctf.net/static/0bf545252b5120845e3b568b9ad0277e/flag.txt.en
/// skipped ///
# ls
ende.py  flag.txt.en  pw.txt
# python3 ende.py 
Usage: ende.py (-e/-d) [file]
# python3 ende.py -d flag.txt.en 
Please enter the password:
# cat pw.txt | python3 ende.py -d flag.txt.en 
Please enter the password:picoCTF{4p0110_1n_7h3_h0us3_6008014f}

"apollo in the house"(?)

Wave a flag

Description
Can you invoke help flags for a tool or binary? This program has extraordinarily helpful information...

# wget https://mercury.picoctf.net/static/b28b6021d6040b086c2226ebeb913bc2/warm
/// skipped ///
# file warm
warm: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=b11c22752c901adc13ba1ce86eda9d5516f22763, with debug_info, not stripped
# chmod +x warm 
# ./warm 
Hello user! Pass me a -h to learn what I can do!
# ./warm -h
Oh, help? I actually don't do much, but I do have this flag here: picoCTF{b1scu1ts_4nd_gr4vy_d6969390}

"biscuits and gravy"

Nice netcat

Description
There is a nice program that you can talk to by using this command in a shell: $ nc mercury.picoctf.net 22342, but it doesn't speak English...

# nc mercury.picoctf.net 22342
112 
105 
99 
111 
67 
84 
70 
123 
103 
48 
48 
100 
95 
107 
49 
116 
116 
121 
33 
95 
110 
49 
99 
51 
95 
107 
49 
116 
116 
121 
33 
95 
53 
102 
98 
53 
101 
53 
49 
100 
125 
10 

パッと見文字コードでしょう。

solver.py

from pwn import remote

r = remote("mercury.picoctf.net", 22342)
while True:
    try:
        c = chr(int(r.recvline().strip()))
        if c != "":
            print(c, end="")
    except EOFError as e:
        r.close()
        break
# python3 solver.py 
[+] Opening connection to mercury.picoctf.net on port 22342: Done
picoCTF{g00d_k1tty!_n1c3_k1tty!_5fb5e51d}
[*] Closed connection to mercury.picoctf.net port 22342

"good kitty! nice kitty!"

Static ain't always noise

Description
Can you look at the data in this binary: static? This BASH script might help!

# wget https://mercury.picoctf.net/static/ec4dbd8898ade34e1d60d5b70c1b8c8c/static
/// skipped ///
# wget https://mercury.picoctf.net/static/ec4dbd8898ade34e1d60d5b70c1b8c8c/ltdis.sh
/// skipped ///
# file static
static: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=639391a8b15c579d69659462d3c935fa61693f17, not stripped
# chmod +x static 
# ./static 
Oh hai! Wait what? A flag? Yes, it's around here somewhere!
# cat ltdis.sh 
#!/bin/bash



echo "Attempting disassembly of $1 ..."


#This usage of "objdump" disassembles all (-D) of the first file given by 
#invoker, but only prints out the ".text" section (-j .text) (only section
#that matters in almost any compiled program...

objdump -Dj .text $1 > $1.ltdis.x86_64.txt


#Check that $1.ltdis.x86_64.txt is non-empty
#Continue if it is, otherwise print error and eject

if [ -s "$1.ltdis.x86_64.txt" ]
then
        echo "Disassembly successful! Available at: $1.ltdis.x86_64.txt"

        echo "Ripping strings from binary with file offsets..."
        strings -a -t x $1 > $1.ltdis.strings.txt
        echo "Any strings found in $1 have been written to $1.ltdis.strings.txt with file offset"



else
        echo "Disassembly failed!"
        echo "Usage: ltdis.sh <program-file>"
        echo "Bye!"
fi

シェルスクリプトはディスアセンブルしてるっぽい。
そうだとすれば、stringsでフラグ取れるのでは?(最初にテキストセクションがなんちゃらって書いてあるし)

# strings static /lib64/ld-linux-x86-64.so.2
libc.so.6
puts
__cxa_finalize
__libc_start_main
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
AWAVI
AUATL
[]A\A]A^A_
Oh hai! Wait what? A flag? Yes, it's around here somewhere!
;*3$"
picoCTF{d15a5m_t34s3r_98d35619}
GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.7698
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
static.c
__FRAME_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
_ITM_deregisterTMCloneTable
puts@@GLIBC_2.2.5
_edata
__libc_start_main@@GLIBC_2.2.5
__data_start
__gmon_start__
__dso_handle
_IO_stdin_used
__libc_csu_init
__bss_start
main
__TMC_END__
_ITM_registerTMCloneTable
flag
__cxa_finalize@@GLIBC_2.2.5
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.data
.bss
.comment
# strings static  | grep pico
picoCTF{d15a5m_t34s3r_98d35619}

"disasm teaser"

Tab, Tab, Attack

Description
Using tabcomplete in the Terminal will add years to your life, esp. when dealing with long rambling directory structures and filenames: Addadshashanammu.zip

# unzip Addadshashanammu.zip Archive:  Addadshashanammu.zip
   creating: Addadshashanammu/
   creating: Addadshashanammu/Almurbalarammi/
   creating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/
   creating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/
   creating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/
   creating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/
   creating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/Ularradallaku/
  inflating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/Ularradallaku/fang-of-haynekhtnamet  
# file Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/Ularradallaku/fang-of-haynekhtnamet
Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/Ularradallaku/fang-of-haynekhtnamet: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=55548d0314fdf7999b966728d19712cdf8a52e58, not stripped
# strings Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/Ularradallaku/fang-of-haynekhtnamet | grep pico
*ZAP!* picoCTF{l3v3l_up!_t4k3_4_r35t!_f3553887}

"level up! take a rest!"

Magikarp Ground Mission

Description
Do you know how to move between directories and read files in the shell? Start the container, `ssh` to it, and then `ls` once connected to begin. Login via `ssh` as `ctf-player` with the password, `481e7b14`

インスタンスを起動させてから、指定されたサーバ・ポートにアクセス

# ssh ctf-player@venus.picoctf.net -p 54159
ctf-player@venus.picoctf.net's password: 
/// skipped ///
ctf-player@pico-chall$ ls
1of3.flag.txt  instructions-to-2of3.txt
ctf-player@pico-chall$ cat 1of3.flag.txt 
picoCTF{xxsh_
ctf-player@pico-chall$ cat instructions-to-2of3.txt 
Next, go to the root of all things, more succinctly `/`
ctf-player@pico-chall$ cd /
ctf-player@pico-chall$ ls
2of3.flag.txt  dev   instructions-to-3of3.txt  media  proc  sbin  tmp
bin            etc   lib                       mnt    root  srv   usr
boot           home  lib64                     opt    run   sys   var
ctf-player@pico-chall$ cat 2of3.flag.txt 
0ut_0f_\/\/4t3r_
ctf-player@pico-chall$ cat instructions-to-3of3.txt 
Lastly, ctf-player, go home... more succinctly `~`
ctf-player@pico-chall$ cd ~
ctf-player@pico-chall$ ls
3of3.flag.txt  drop-in
ctf-player@pico-chall$ cat 3of3.flag.txt 
1118a9a4}

picoCTF{xxsh_0ut_0f_\/\/4t3r_1118a9a4}

"xxsh out of water"

picoCTF 2021 Crypto (4) New Caesar

New Caesar
| 60 points
Tags:
AUTHOR: MADSTACKS

Description
We found a brand new type of encryption, can you break the secret code? (Wrap with picoCTF{}) lkmjkemjmkiekeijiiigljlhilihliikiliginliljimiklligljiflhiniiiniiihlhilimlhijil new_caesar.py

new_caesar.py

import string

LOWERCASE_OFFSET = ord("a")
ALPHABET = string.ascii_lowercase[:16]

def b16_encode(plain):
	enc = ""
	for c in plain:
		binary = "{0:08b}".format(ord(c))
		enc += ALPHABET[int(binary[:4], 2)]
		enc += ALPHABET[int(binary[4:], 2)]
	return enc

def shift(c, k):
	t1 = ord(c) - LOWERCASE_OFFSET
	t2 = ord(k) - LOWERCASE_OFFSET
	return ALPHABET[(t1 + t2) % len(ALPHABET)]

flag = "redacted"
key = "redacted"
assert all([k in ALPHABET for k in key])
assert len(key) == 1

b16 = b16_encode(flag)
enc = ""
for i, c in enumerate(b16):
	enc += shift(c, key[i % len(key)])
print(enc)

平文にb16_encodeした後、keyでシフトしている。
b16_encodeは、平文の文字コードを4ビットごとに分けて、それぞれを英小文字の[a-p]に割り当てているみたい。
keyは、assert文から、[a-p]のいずれか。
なので、keyを総当たりでデコードしてみる。

import string

LOWERCASE_OFFSET = ord("a")
ALPHABET = string.ascii_lowercase[:16]

def deshift(c, k):
	t1 = ord(c) - LOWERCASE_OFFSET
	t2 = ord(k) - LOWERCASE_OFFSET
	return ALPHABET[(t1 - t2) % len(ALPHABET)]

def b16_decode(enc):

    ### b16_encode
    # def b16_encode(plain):
	# enc = ""
	# for c in plain:
	# 	binary = "{0:08b}".format(ord(c))
	# 	enc += ALPHABET[int(binary[:4], 2)]
	# 	enc += ALPHABET[int(binary[4:], 2)]
	# return enc

    plain = ""
    for i, c in enumerate(enc):
        if i % 2 == 0:
            upper_byte = ord(c) - LOWERCASE_OFFSET
        else:
            lower_byte = ord(c) - LOWERCASE_OFFSET
            plain += chr(upper_byte * 16 + lower_byte)

    return plain

c = "lkmjkemjmkiekeijiiigljlhilihliikiliginliljimiklligljiflhiniiiniiihlhilimlhijil "

for k in ALPHABET:
    _c = ""
    for _ in c:
        _c += deshift(_, k)
    #print(_c)
    plain = b16_decode(_c)
    print("key '{}': {}".format(k, plain))
# python3 exploit.py 
key 'a': ºÉ¤ÉÊ
              ¤¹·¸¸¹»¹
···
key 'b': ©¸¸¹sxwu¨¦zv§yzu|§¨{yªu¨t¦|w|wv¦z{¦xz
key 'c': §¨bgfdiehidkjhdckfkfeijgi
key 'd': qQqVUS
               XT
WXSZ
YWSR
    ZUZUT
         XY
           VX
key 'e': v
`
@`EDBusGCtFGBItuHFwBuAsIDIDCsGHsEG
key 'f': et_tu?_431db62c5618cd75f1d0b83832b67b46
key 'g': TcNcd.N#" SQ%!R$% 'RS&$U S/Q'"'"!Q%&Q#%
key 'h': CR=RS=B@AABDB@@@
key 'i': 2A,AB
???           ,1?00131
key 'j': !01ûÿý .òþ/ñòýô/ óñ"ý ü.ôÿôÿþ.òó.ðò
key 'k': /
/ ê
ïîìáíàáìãâàìëãîãîíáâïá
key 'l': ùÙùÞÝÛ
ÑßÛÚ           ÐÜ
    ÒÝÒÝÜ
         ÐÑ
           ÞÐ
ÈèÍÌÊýûÏËüÎÏÊÁüýÀÎÿÊýÉûÁÌÁÌËûÏÀûÍÏ
key 'n': íü×üý·×¼»¹ì꾺뽾¹°ë쿽î¹ì¸ê°»°»ºê¾¿ê¼¾
key 'o': ÜëÆëì¦Æ«ª¨ÛÙ­©Ú¬­¨¯ÚÛ®¬Ý¨Û§Ù¯ª¯ª©Ù­®Ù«­
key 'p': ËÚµÚÛµÊÈÊÊÈ

よくわからないが、

key 'f': et_tu?_431db62c5618cd75f1d0b83832b67b46

自然言語っぽい("et tu?"の部分がフランス語)ので、これを入れてみると通った。

picoCTF 2021 Crypto (3) Easy Peasy

Easy Peasy
| 40 points
Tags:
AUTHOR: MADSTACKS

Description
A one-time pad is unbreakable, but can you manage to recover the flag? (Wrap with picoCTF{}) nc mercury.picoctf.net 58913 otp.py

otp.py

#!/usr/bin/python3 -u
import os.path

KEY_FILE = "key"
KEY_LEN = 50000
FLAG_FILE = "flag"


def startup(key_location):
	flag = open(FLAG_FILE).read()
	kf = open(KEY_FILE, "rb").read()

	start = key_location
	stop = key_location + len(flag)

	key = kf[start:stop]
	key_location = stop

	result = list(map(lambda p, k: "{:02x}".format(ord(p) ^ k), flag, key))
	print("This is the encrypted flag!\n{}\n".format("".join(result)))

	return key_location

def encrypt(key_location):
	ui = input("What data would you like to encrypt? ").rstrip()
	if len(ui) == 0 or len(ui) > KEY_LEN:
		return -1

	start = key_location
	stop = key_location + len(ui)

	kf = open(KEY_FILE, "rb").read()

	if stop >= KEY_LEN:
		stop = stop % KEY_LEN
		key = kf[start:] + kf[:stop]
	else:
		key = kf[start:stop]
	key_location = stop

	result = list(map(lambda p, k: "{:02x}".format(ord(p) ^ k), ui, key))

	print("Here ya go!\n{}\n".format("".join(result)))

	return key_location


print("******************Welcome to our OTP implementation!******************")
c = startup(0)
while c >= 0:
	c = encrypt(c)

入力文だけkeyをオフセットさせながら、好きな文字を暗号化させられる。
つまり、keyが50000字なので一周させればよさそう。
と思って以下のような感じでやたらうまくいかなかった。。

from pwn import remote

r = remote("mercury.picoctf.net", 58913)

r.recvuntil("This is the encrypted flag!\n")
c = r.recvuntil("\n").strip()
r.recvuntil("encrypt? ")

r.sendline("\x00" * 50000)
r.recvuntil("Here ya go!\n")
k = r.recvuntil("\n").strip()[-len(c):]

r.close()

print(c)
print(k)

def otp(message, key):
    buf = ""
    b_message = int(message, 16).to_bytes(len(message)//2, byteorder="big")
    b_key = int(key, 16).to_bytes(len(b_message), byteorder="big")
    for m, k in zip(b_message, b_key):
        buf += chr(m ^ k)

    return buf

print(otp(c, k))
# python3 exploit.py [+] Opening connection to mercury.picoctf.net on port 58913: Done
[*] Closed connection to mercury.picoctf.net port 58913
b'51124f4d194969633e4b52026f4c07513a6f4d05516e1e50536c4954066a1c57'
b'7830316a705c7865385c7838314176685c7839323f5c7864315c7861615c7838'
)"~'i\x15\x06\x17:^q9f\x177n2f4b015g6do

そこで、とりあえず50000字に至るまで入力し、再度フラグ長分だけなげてみたらいけた。

from pwn import remote

r = remote("mercury.picoctf.net", 58913)

r.recvuntil("This is the encrypted flag!\n")
c = r.recvuntil("\n").strip()
r.recvuntil("encrypt? ")

r.sendline("\x00" * (50000 - len(c)//2))

r.recvuntil("Here ya go!\n")
#k = r.recvuntil("\n").strip()[-len(c):]

r.recvuntil("encrypt? ")

r.sendline("\x00" * (len(c)//2))

r.recvuntil("Here ya go!\n")
k = r.recvuntil("\n").strip()

r.close()

print(c)
print(k)

def otp(message, key):
    # "".join(list(map(lambda p, k: "{}".format(chr(p ^ k)), int(c,16).to_bytes(len(c)//2, byteorder="big"), int(k,16).to_bytes(len(c)//2, byteorder="big"))))
    buf = ""
    b_message = int(message, 16).to_bytes(len(message)//2, byteorder="big")
    b_key = int(key, 16).to_bytes(len(b_message), byteorder="big")
    for m, k in zip(b_message, b_key):
        buf += chr(m ^ k)

    return buf

print(otp(c, k))
# python3 exploit.py 
[+] Opening connection to mercury.picoctf.net on port 58913: Done
[*] Closed connection to mercury.picoctf.net port 58913
b'51124f4d194969633e4b52026f4c07513a6f4d05516e1e50536c4954066a1c57'
b'62272a2e7b7d5b505c7830365c783063595c7866325c7864625c7865655c7865'
35ecb423b3b43472c35cc2f41011c6d2

なぜだかしばらくよくわからなかったが、ふと、keyファイルが50000バイトより長い場合、一気に長いものを投げると50000字を超えた分までkeyとして使われてるってことなんだな、と思いつき、ローカルで試したらたぶんそうだった。

		key = kf[start:] + kf[:stop]

のところで、kf[start:KEY_LEN]にしてないのが原因ですね・・・

picoCTF 2021 Crypto (2) Mind your Ps and Qs

Mind your Ps and Qs
 | 20 points
Tags: 
AUTHOR: SARA

Description
In RSA, a small e value can be problematic, but what about N? Can you decrypt this? values
# cat values 
Decrypt my super sick RSA:
c: 843044897663847841476319711639772861390329326681532977209935413827620909782846667
n: 1422450808944701344261903748621562998784243662042303391362692043823716783771691667
e: 65537

よくわからないが、問題文からnが分解できるということなんだろうから、とりあえずnを無理矢理素因数分解してみる。

これを利用。
Integer factorization calculator

1422 450808 944701 344261 903748 621562 998784 243662 042303 391362 692043 823716 783771 691667 (82 digits) = 2159 947535 959146 091116 171018 558446 546179 (40 digits) × 658558 036833 541874 645521 278345 168572 231473 (42 digits)
Number of divisors: 4

Sum of divisors: 1422 450808 944701 344261 903748 621562 998784 904380 026672 892383 428681 273080 510790 469320 (82 digits)

Euler's totient: 1422 450808 944701 344261 903748 621562 998783 582944 057933 890341 955406 374353 056752 914016 (82 digits)

Möbius: 1

n = a² + b² + c² + d²

a = 23153 753416 263562 304085 113679 610908 542901 (41 digits)

b = 21879 576025 097055 792772 666607 707345 158969 (41 digits)

c = 20108 191366 928777 506197 370908 995056 798757 (41 digits)

d = 1816 398798 869307 932329 158302 569753 005684 (40 digits)

Time elapsed: 0d 0h 6m 8.1s

Modular multiplications:

ECM: 78620336
Probable prime checking: 1389
SIQS: 128195
Sum of squares: 1124
SIQS:

780030 polynomials sieved
440269 sets of trial divisions
15206 smooth congruences found (1 out of every 4157971 values)
171081 partial congruences found (1 out of every 369568 values)
16049 useful partial congruences
Size of binary matrix: 28814 × 28019
Timings:

Probable prime test of 3 numbers: 0d 0h 0m 0.0s
Factoring 1 number using ECM: 0d 0h 0m 12.5s
Factoring 1 number using SIQS: 0d 0h 5m 55.6s
Written by Dario Alpern. Last updated on 20 May 2021.

この2つの整数(40/42 digits)をp,qとしてdを求めてplaintextを求めればいいはず。

import gmpy
from Crypto.Util.number import long_to_bytes

qfile = "values"
"""
Decrypt my super sick RSA:
c: 843044897663847841476319711639772861390329326681532977209935413827620909782846667
n: 1422450808944701344261903748621562998784243662042303391362692043823716783771691667
e: 65537
"""
c, n, e = ([int(_[3:]) for _ in open(qfile).read().split("\n")[1:]])

p, q = [2159947535959146091116171018558446546179, 658558036833541874645521278345168572231473]

phi = (p-1)*(q-1)
d = gmpy.invert(e, phi)

m = int(pow(c, d, n))

print("d: {}".format(d))
print("m: {}".format(m))
print("p: {}".format(long_to_bytes(m)))
# python3 exploit.py 
d: 975120122884150896343356420256053234758228648361853546720066993334766006694511009
m: 13016382529449106065927291425342535437996222135352905256639555294957886055592061
p: b'picoCTF{sma11_N_n0_g0od_00264570}'

Small N no good!

なお、RSA問題については以下のページが参考になる。
inaz2.hatenablog.com