A&D of Network Security - Lab 7
tags: Practicum of A&D of NS
NTU
Background
What is foremost and How to use it?
RSA CTF
Exercise - RSA
Given
1 |
|
Then I can use decrypt function to fetch plaintext.
Flag(hex): 12058e43d9e0c22559c19774
:::spoiler source code
from Crypto.Util.number import long_to_bytes, inverse, bytes_to_long
p = 9648423029010515676590551740010426534945737639235739800643989352039852507298491399561035009163427050370107570733633350911691280297777160200625281665378483
q = 11874843837980297032092405848653656852760910154543380907650040190704283358909208578251063047732443992230647903887510065547947313543299303261986053486569407
e = 65537
c = 83208298995174604174773590298203639360540024871256126892889661345742403314929861939100492666605647316646576486526217457006376842280869728581726746401583705899941768214138742259689334840735633553053887641847651173776251820293087212885670180367406807406765923638973161375817392737747832762751690104423869019034
n = p * q
phi = (q-1)*(p-1)
d = inverse(e, phi)
print(long_to_bytes(pow(c,d,n)).hex())
:::
Exercise - Decrypt_RSA
Given public-key.pem
and flag.txt
File: public-key.pem
1 |
|
- Recon
Obviously, you can notice that public key file is generated by such like
openssl
tool. So, there’s a way to turn it to text. - Transform
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16$ openssl rsa -pubin -in public-key.pem -text RSA Public-Key: (640 bit) Modulus: 00:ae:5b:b4:f2:66:00:32:59:cf:9a:6f:52:1c:3c: 03:41:01:76:cf:16:df:53:95:34:76:ea:e3:b2:1e: de:6c:3c:7b:03:bd:ca:20:b3:1c:00:67:ff:a7:97: e4:e9:10:59:78:73:ee:f1:13:a6:0f:ec:cd:95:de: b5:b2:bf:10:06:6b:e2:22:4a:ce:29:d5:32:dc:0b: 5a:74:d2:d0:06:f1 Exponent: 65537 (0x10001) writing RSA key -----BEGIN PUBLIC KEY----- MGwwDQYJKoZIhvcNAQEBBQADWwAwWAJRAK5btPJmADJZz5pvUhw8A0EBds8W31OV NHbq47Ie3mw8ewO9yiCzHABn/6eX5OkQWXhz7vETpg/szZXetbK/EAZr4iJKzinV MtwLWnTS0AbxAgMBAAE= -----END PUBLIC KEY-----
Then after the transformation, you can see that
n=p*q=0x00ae...
ande=65537
- Hex to Decimal
>>> int("00ae5bb4f266003259cf9a6f521c3c03410176cf16df53953476eae3b21ede6c3c7b03bdca20b31c0067ffa797e4e910597873eef113a60feccd95deb5b2bf10066be2224ace29d532dc0b5a74d2d006f1", 16) 3107418240490043721350750035888567930037346022842727545720161948823206440518081504556346829671723286782437916272838033415471073108501919548529007337724822783525742386454014691736602477652346609
-
Factoring Small
n
Just using the online tool and you’ll getp
andq
p=1634733645809253848443133883865090859841783670033092312181110852389333100104508151212118167511579
q=1900871281664822113126851573935413975471896789968515493666638539088027103802104498957191261465571
- Decrypt Cipher
from Crypto.Util.number import long_to_bytes, inverse, bytes_to_long, isPrime from base64 import b64decode cipher = open("./flag.txt", "rb").read().hex() cipher = int(cipher, 16) p = 1634733645809253848443133883865090859841783670033092312181110852389333100104508151212118167511579 q = 1900871281664822113126851573935413975471896789968515493666638539088027103802104498957191261465571 e = 65537 n = p * q phi = (q-1)*(p-1) d = inverse(e, phi) print(bytes.fromhex(long_to_bytes(pow(cipher,d,n)).hex()).decode("cp437"))
Flag:
FLAG_IS_WeAK_rSA
Stego CTF
Exercise 1 - zip
Extension
- Use
binwalk
to Recon1
2
3
4
5
6
7
8
9
10$ binwalk Exercise\ 1\ -\ example.jpg DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 JPEG image data, EXIF standard 12 0xC TIFF image data, big-endian, offset of first image directory: 8 9298 0x2452 TIFF image data, little-endian offset of first image directory: 662 9692 0x25DC JPEG image data, JFIF standard 1.01 14241 0x37A1 Copyright string: "Copyright 2003 Apple Computer Inc., all rights reserved." 1972141 0x1E17AD Zip archive data, at least v1.0 to extract, compressed size: 20, uncompressed size: 20, name: secret.txt 1972309 0x1E1855 End of Zip archive, footer length: 22
You can see that it contained a
zip
file at the end of data - Change Extension
Thus, you can change the extension manually and
unzip
it - Get Secret
:::spoiler secret flag
supa_secret_flagzor
:::
Exercise 2 - Foremost
- Recon
1
2
3
4
5
6
7
8
9
10
11
12
13$ pngcheck Exercise\ 2\ -\ PurpleThing.png Exercise 2 - PurpleThing.png EOF while reading CRC value ERROR: Exercise 2 - PurpleThing.png $ binwalk Exercise\ 2\ -\ PurpleThing.png DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 PNG image, 3200 x 2953, 8-bit/color RGBA, non-interlaced 85 0x55 Zlib compressed data, best compression 2757 0xAC5 Zlib compressed data, best compression 765455 0xBAE0F JPEG image data, JFIF standard 1.01 765485 0xBAE2D TIFF image data, big-endian, offset of first image directory: 8 1809691 0x1B9D1B StuffIt Deluxe Segment (data): f
First, I used
pngcheck
to observe the data structure and it returned CRC error means something wrong at the end of file. Therefore, I usedbinwalk
to check the extra information. It seemed has another file in it. - Use
Foremost
to parse hiding files1
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$ foremost -v Exercise\ 2\ -\ PurpleThing.png Foremost version 1.5.7 by Jesse Kornblum, Kris Kendall, and Nick Mikus Audit File Foremost started at Mon Apr 10 22:47:57 2023 Invocation: foremost -v Exercise 2 - PurpleThing.png Output directory: /mnt/d/NTU/First Year/2nd semester/Practicum of Attacking and Defense of Network Security/Lab/Lec07/Practice/output Configuration file: /etc/foremost.conf Processing: Exercise 2 - PurpleThing.png |------------------------------------------------------------------ File: Exercise 2 - PurpleThing.png Start: Mon Apr 10 22:47:57 2023 Length: 2 MB (2354256 bytes) Num Name (bs=512) Size File Offset Comment 0: 00001495.jpg 1 MB 765455 *| Finish: Mon Apr 10 22:47:57 2023 1 FILES EXTRACTED jpg:= 1 ------------------------------------------------------------------ Foremost finished at Mon Apr 10 22:47:57 2023
Then it’ll extract a folder named
output
:::spoilersecret flag
:::
Exercise 3 - Unzip twice
- Use
binwalk
to recon1
2
3
4
5
6
7$ binwalk Exercise\ 3\ -\ stego2.jpg DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 JPEG image data, JFIF standard 1.01 40804 0x9F64 Zip archive data, at least v2.0 to extract, compressed size: 32993, uncompressed size: 33783, name: got2.jpg 73941 0x120D5 End of Zip archive, footer length: 22
- Unzip it
-
binwalk
again1
2
3
4
5
6
7$ binwalk got2.jpg DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 JPEG image data, JFIF standard 1.02 33587 0x8333 Zip archive data, at least v1.0 to extract, compressed size: 32, uncompressed size: 32, name: txt.txt 33761 0x83E1 End of Zip archive, footer length: 22
- Unzip it again
- Get flag
:::spoiler
Flag:
6307834008eb8edbe18c7a20ee4a909d
:::
Exercise 4
- Recon
1
2
3
4
5
6
7
8$ pngcheck -cv Exercise\ 4\ -\ stego1.png File: Exercise 4 - stego1.png (11037 bytes) chunk IHDR at offset 0x0000c, length 13 800 x 800 image, 24-bit RGB, non-interlaced chunk IDAT at offset 0x00025, length 10980 zlib: deflated, 32K window, default compression chunk IEND at offset 0x02b15, length 0 No errors detected in Exercise 4 - stego1.png (3 chunks, 99.4% compression).
Seems there is nothing special information however, TA’s hint is
png filter
. Refer to W3C spec, I am aware that there are several filter types that can be applied, such as None(byte 0x0)
, Sub(byte 0x1)
, Up(byte 0x2)
etc.Bytes of these filter types can be used to hide information, i.e. the flag, in the PNG. In our case, we have to decompress the PNG
IDAT
chunk data and extract the filter type bytes from the decompressed data. - Decompressed Flag by Using Script below
./Exercise\ 4-exp.py Exercise\ 4\ -\ stego1.png PNG Signature: (b'\x89', b'P', b'N', b'G', b'\r', b'\n', b'\x1a', b'\n') Pos : 8 Type: b'IHDR' Size: 13 CRC : b'5412913F' Pos : 33 Type: b'IDAT' Size: 10980 CRC : b'98F96EEB' Pos : 11025 Type: b'IEND' Size: 0 CRC : b'AE426082' Data length in PNG file : 10980 Decompressed data length: 1920800 Flag: DrgnS{WhenYouGazeIntoThePNGThePNGAlsoGazezIntoYou}
:::spoiler source code
#!/usr/bin/env python from struct import unpack from binascii import hexlify, unhexlify import sys, zlib # Returns [Position, Chunk Size, Chunk Type, Chunk Data, Chunk CRC] def getChunk(buf, pos): a = [] a.append(pos) size = unpack('!I', buf[pos:pos+4])[0] # Chunk Size a.append(buf[pos:pos+4]) # Chunk Type a.append(buf[pos+4:pos+8]) # Chunk Data a.append(buf[pos+8:pos+8+size]) # Chunk CRC a.append(buf[pos+8+size:pos+12+size]) return a def printChunk(buf, pos): print('Pos : '+str(pos)+'') print('Type: ' + str(buf[pos+4:pos+8])) size = unpack('!I', buf[pos:pos+4])[0] print('Size: ' + str(size)) #print('Cont: ' + str(hexlify(buf[pos+8:pos+8+size]))) print('CRC : ' + str(hexlify(buf[pos+size+8:pos+size+12]).upper())) print if len(sys.argv)!=2: print('Usage: ./this Stegano_PNG') sys.exit(2) with open(sys.argv[1], 'rb') as f: buf = f.read() pos=0 print("PNG Signature: " + str(unpack('cccccccc', buf[pos:pos+8]))) pos+=8 chunks = [] for i in range(3): chunks.append(getChunk(buf, pos)) printChunk(buf, pos) pos+=unpack('!I',chunks[i][1])[0]+12 decompressed = zlib.decompress(chunks[1][3]) # Decompressed data length = height x (width * 3 + 1) print("Data length in PNG file : ", len(chunks[1][3])) print("Decompressed data length: ", len(decompressed)) height = unpack('!I',(chunks[0][3][4:8]))[0] width = unpack('!I',(chunks[0][3][:4]))[0] blocksize = width * 3 + 1 filterbits = '' for i in range(0,len(decompressed),blocksize): bit = unpack('2401c', decompressed[i:i+blocksize])[0] if bit == b'\x00': filterbits+='0' elif bit == b'\x01': filterbits+='1' else: print('Bit is not 0 or 1... Default is 0 - MAGIC!') sys.exit(3) s = filterbits endianess_filterbits = [filterbits[i:i+8][::-1] for i in range(0, len(filterbits), 8)] flag = '' for x in endianess_filterbits: if x=='00000000': break flag += unhexlify('%x' % int('0b'+str(x), 2)).decode() print('Flag: ' + flag)
:::
Exercise 5 - Change Palette
-
Recon First, I used online tool to fetch some info but all of them are useless. So, I used
stegsolve.jar
to analyze the figure, and something blurry appeared at the right of picture shown below - Try to change palette
I found a useful code on Stack Overflow, and after some debugging, I can use it successfully. This program is aimed to allow us to write out 256 images, each one highlighting a single entry in white while blacking out the others:
$ for i in {0..255}; do ./change_palette.py doge_stege.png "single-color-${i}.png" "${i}"; done
:::info At the first time using, you should uncomment line 32 and comment line 34 to find which page can be decrypted :::
You can observe that
single-color-127.png
has some strings that we met instegsolve.jar
, so that is the magic number that we can continue decrypting. - Continue changing palette
$ for i in {0..128}; do ./change_palette.py doge_stege.png "range-color-127+${i}.png" "${i}"; done
:::info Note that you should uncomment line 34 and comment line 32 to decrypt it further. :::
You can notice that most of the results have clearly flag strings in the pictures. :::spoiler source code ```python= #!/usr/bin/env python
import sys import struct from zlib import crc32 import os
PNG file format signature
pngsig = b’\x89PNG\r\n\x1a\n’
def swap_palette(filename, n): # open in read+write mode with open(filename, ‘r+b’) as f: f.seek(0) # verify that we have a PNG file if f.read(len(pngsig)) != pngsig: raise RuntimeError(‘not a png file!’)
1 |
|
if name == ‘main’: import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) swap_palette(sys.argv[2], int(sys.argv[3])) ``` :::
Exercise 6
TA’s Hint: LSB and brute force
- Fetch LSB from Each Pixel
from PIL import Image FLAG = "" flag_image = Image.open("./Exercise 6 - bonas.png") pixel = flag_image.getdata() for i in pixel: FLAG += bin(i)[-1]
- Observe the data type
After getting LSB from each pixel, you can observe the extension of this file from the beginning bytes
... for i in range(4): print(chr(int(FLAG[i*8:(i+1)*8], 2))) ...
The output is:
Rar!
- Transform a proper file
So, we can modify the file extension and store it in bytes.
... output = open("./data.rar", "wb") for j in range(0, len(FLAG), 8): output.write(chr(int(FLAG[j:j+8], 2)).encode()) ...
- Brute force to decrypt it
However if we’d like to unzip it, it needs 5 char password. So, I found a wordlist in this page and try to unzip it.
... import subprocess, re password = open("password.txt", "r").read().split(" ") for passwd in password: # print(passwd) result = subprocess.getstatusoutput("unrar x data.rar - inul -p" + passwd) if result[0] == 0: print("Sucess!! Password is {}".format(passwd)) break ...
- After Unzip it
You’ll get a
flag.txt
and the flag is:LSB_is_ubiquitous
Reference
Exercise Decrypt_RSA
How do I use the openssl command to decode a public key .PEM file?
Exercise 4
PNG (Portable Network Graphics) Specification CONFidence CTF Teaser A PNG Tale - Write Up Misc 总结 —-隐写术之图片隐写(二)
Exercise 5
Plaid CTF 2014: doge_stege doge_stege write up - 第8回資料 二進制處理方式