# CryptoHack – General challenges ## Encoding Chuỗi 5 challenge giới thiệu các dạng mã hóa thông dụng. ### ASCII ASCII is a 7-bit encoding standard which allows the representation of text using the integers 0-127. Using the below integer array, convert the numbers to their corresponding ASCII characters to obtain a flag. ```python [99, 114, 121, 112, 116, 111, 123, 65, 83, 67, 73, 73, 95, 112, 114, 49, 110, 116, 52, 98, 108, 51, 125] ``` #### Solution Bài này yêu cầu ta chuyển từng phần tử trong list từ decimal sang mã ASCII, ta dùng hàm `chr()` và có flag. ```python FLAG = [99, 114, 121, 112, 116, 111, 123, 65, 83, 67, 73, 73, 95, 112, 114, 49, 110, 116, 52, 98, 108, 51, 125] print(''.join([chr(i) for i in FLAG])) ``` ``` crypto{ASCII_pr1nt4bl3} ``` ### Hex When we encrypt something the resulting ciphertext commonly has bytes which are not printable ASCII characters. If we want to share our encrypted data, it's common to encode it into something more user-friendly and portable across different systems. Hexadecimal can be used in such a way to represent ASCII strings. First each letter is converted to an ordinal number according to the ASCII table (as in the previous challenge). Then the decimal numbers are converted to base-16 numbers, otherwise known as hexadecimal. The numbers can be combined together, into one long hex string. Included below is a flag encoded as a hex string. Decode this back into bytes to get the flag. ``` 63727970746f7b596f755f77696c6c5f62655f776f726b696e675f776974685f6865785f737472696e67735f615f6c6f747d ``` #### Solution Bài này giới hiệu về cách mã hóa xâu bằng cách chuyển về mã hex. Ta chỉ cần dùng hàm `bytes.fromhex()` để chuyển từ mã hex về dạng bytes. Có thể thêm hàm `decode()` để chuyển từ bytes sang xâu. ```python print(bytes.fromhex("63727970746f7b596f755f77696c6c5f62655f776f726b696e675f776974685f6865785f737472696e67735f615f6c6f747d").decode()) ``` ``` crypto{You_will_be_working_with_hex_strings_a_lot} ``` ### Base64 Another common encoding scheme is Base64, which allows us to represent binary data as an ASCII string using an alphabet of 64 characters. One character of a Base64 string encodes 6 binary digits (bits), and so 4 characters of Base64 encode three 8-bit bytes. Base64 is most commonly used online, so binary data such as images can be easily included into HTML or CSS files. Take the below hex string, decode it into bytes and then encode it into Base64. ``` 72bca9b68fc16ac7beeb8f849dca1d8a783e8acf9679bf9269f7bf ``` #### Solution Mã hóa Base64 là dạng mã hóa thông dụng. Ta làm theo Description là chuyển mã hex đã cho thành bytes bằng `bytes.fromhex()` rồi giải mã base64 bằng `base64.b64encode()`. ```python import base64 print(base64.b64encode(bytes.fromhex("72bca9b68fc16ac7beeb8f849dca1d8a783e8acf9679bf9269f7bf"))) ``` ``` crypto/Base+64+Encoding+is+Web+Safe/ ``` ### Bytes and Bit Integers Convert the following integer back into a message: ```python 11515195063862318899931685488813747395775516287289682636499965282714637259206269 ``` #### Solution Như Description, ta chuyển số bự bự đề cho thành bytes bằng `long_to_bytes()`. Có thể dùng thêm `decode()` để chuyển thành xâu. ```py from Crypto.Util.number import * print(long_to_bytes(11515195063862318899931685488813747395775516287289682636499965282714637259206269).decode()) ``` ``` crypto{3nc0d1n6_4ll_7h3_w4y_d0wn} ``` ### Encoding Challenge Now you've got the hang of the various encodings you'll be encountering, let's have a look at automating it. Can you pass all 100 levels to get the flag? The [13377.py](https://cryptohack.org/static/challenges/13377_43de0a0efed6ed7bd890d1c79db22fb1.py) file attached is the source code for what's running on the server. The pwntools_example.py file provides the start of a solution. For more information about connecting to interactive challenges, see the FAQ. Feel free to skip ahead to the cryptography if you aren't in the mood for a coding challenge! Connect at ``socket.cryptohack.org 13377`` #### Solution ```python from pwn import * from Crypto.Util.number import * import json, codecs d = { "base64": b64d, "hex": unhex, "rot13": lambda s: codecs.encode(s, 'rot_13').encode(), "bigint": lambda s: long_to_bytes(int(s, 0)), "utf-8": bytes } def dec(o): return d[o["type"]](o["encoded"]) io = remote("socket.cryptohack.org", 13377, level="debug") for _ in range(100): o = json.loads(io.recvline()) io.sendline(json.dumps({"decoded": dec(o).decode()})) io.interactive() ``` ``` crypto{3nc0d3_d3c0d3_3nc0d3} ``` ## XOR ### XOR Starter Given the string `label`, XOR each character with the integer `13`. Convert these integers back to a string and submit the flag as ``crypto{new_string}``. #### Solution Câu này giới thiệu về phép Xor nên ta chỉ cần làm như Description là dùng hàm `xor()`. ```python from pwn import xor print(f"crypto{{{xor(b'label', 13).decode()}}}") ``` ``` crypto{aloha} ``` ### XOR Properties Let's break this down. Commutative means that the order of the XOR operations is not important. Associative means that a chain of operations can be carried out without order (we do not need to worry about brackets). The identity is 0, so XOR with 0 "does nothing", and lastly something XOR'd with itself returns zero. Let's put this into practice! Below is a series of outputs where three random keys have been XOR'd together and with the flag. Use the above properties to undo the encryption in the final line to obtain the flag. ```python KEY1 = a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313 KEY2 ^ KEY1 = 37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e KEY2 ^ KEY3 = c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1 FLAG ^ KEY1 ^ KEY3 ^ KEY2 = 04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf ``` #### Solution Đề đã cho ta KEY1 và (KEY2 ^ KEY3) nên ta chỉ việc lấy (FLAG ^ KEY1 ^ KEY2 ^ KEY3) xor với KEY1 và (KEY2^KEY3) là có flag. ```python from Crypto.Util.number import long_to_bytes KEY1 = 0xa6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313 KEY23 = 0xc1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1 FLAG = 0x04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf print(long_to_bytes(KEY1 ^ KEY23 ^ FLAG).decode()) ``` ``` crypto{x0r_i5_ass0c1at1v3} ``` ### Favourite byte For the next few challenges, you'll use what you've just learned to solve some more XOR puzzles. I've hidden some data using XOR with a single byte, but that byte is a secret. Don't forget to decode from hex first. ``` 73626960647f6b206821204f21254f7d694f7624662065622127234f726927756d ``` #### Solution Theo đề thì đoạn mã đã được Xor với 1 byte nào đó. Theo format của flag thì kí tự đầu tiên của mã là 'c' trong "crypto{". Vậy ta Xor kí tự đầu tiên của mã với 'c' để tìm byte đã sử dụng để Xor chuỗi ban đầu. Tiến hành Xor với byte tìm được, ta có flag. ```python from pwn import xor FLAG = "73626960647f6b206821204f21254f7d694f7624662065622127234f726927756d" FLAG = bytes.fromhex(FLAG) print(xor(FLAG, xor(FLAG[0], ord('c'))).decode()) ``` ``` crypto{0x10_15_my_f4v0ur173_by7e} ``` ### You either know, XOR you don't I've encrypted the flag with my secret key, you'll never be able to guess it. ``` 0e0b213f26041e480b26217f27342e175d0e070a3c5b103e2526217f27342e175d0e077e263451150104 ``` #### Solution Ta đã biết format của flag luôn mở đầu với `crypto{`. Thử Xor đoạn mã với `crypto{`, nhìn vào các kí tự đầu và 1 tẹo guessing, ta được key là `myXORkey` ```python from pwn import xor FLAG = "0e0b213f26041e480b26217f27342e175d0e070a3c5b103e2526217f27342e175d0e077e263451150104" FLAG = bytes.fromhex(FLAG) print(xor(FLAG, b'crypto{')) ``` ``` b'myXORke+y_Q\x0bHOMe$~seG8bGURN\x04DFWg)a|\x1dTM!an\x7f' ``` Full code ```python from pwn import xor FLAG = "0e0b213f26041e480b26217f27342e175d0e070a3c5b103e2526217f27342e175d0e077e263451150104" FLAG = bytes.fromhex(FLAG) key = xor(FLAG[:7], b'crypto{') + b'y' # key = b'myXORkey' print(xor(FLAG, key).decode()) ``` ``` crypto{1f_y0u_Kn0w_En0uGH_y0u_Kn0w_1t_4ll} ``` ### Lemur Xor I've hidden two cool images by XOR with the same secret key so you can't see them! [lemur.png](https://cryptohack.org/static/challenges/lemur_ed66878c338e662d3473f0d98eedbd0d.png) [flag.png](https://cryptohack.org/static/challenges/flag_7ae18c704272532658c10b5faad06d74.png) #### Solution Ta thực hiện xor từng bytes ```python from PIL import Image from pwn import xor lemur = Image.open("lemur.png") flag = Image.open("flag.png") leak_bytes = xor(lemur.tobytes(), flag.tobytes()) leak = Image.frombytes(flag.mode, flag.size, leak_bytes) leak.save('leak.png') ``` ![image](https://hackmd.io/_uploads/rJmxK6KJA.png) ## MATHEMATICS https://hackmd.io/kV50eb8XToCx5DG2Vd5J_Q ## DATA FORMATS ### Privacy-Enhanced Mail? As we've seen in the encoding section, cryptography involves dealing with data in a wide variety of formats: big integers, raw bytes, hex strings and more. A few structured formats have been standardised to help send and receive cryptographic data. It helps to be able to recognise and manipulate these common data formats. PEM is a popular format for sending keys, certificates, and other cryptographic material. It looks like: ``` -----BEGIN RSA PUBLIC KEY----- MIIBCgKC... (a whole bunch of base64) -----END RSA PUBLIC KEY----- ``` It wraps base64-encoded data by a one-line header and footer to indicate how to parse the data within. Perhaps unexpectedly, it's important for there to be the correct number of hyphens in the header and footer, otherwise cryptographic tools won't be able to recognise the file. The data that gets base64-encoded is DER-encoded ASN.1 values. Confused? The resources linked below have more information about what these acronyms mean but the complexity is there for historical reasons and going too deep into the details may drive you insane. Extract the private key d as a decimal integer from this PEM-formatted RSA key. [privacy_enhanced_mail.pem](https://cryptohack.org/static/challenges/privacy_enhanced_mail_1f696c053d76a78c2c531bb013a92d4a.pem) #### Solution Theo yêu cầu đề thì ta chỉ cần mở file PEM và lấy private key `d` trong đó. ```python from Crypto.PublicKey import RSA key = RSA.import_key(open("privacy_enhanced_mail.pem").read()) print(key.d) ``` ```python 15682700288056331364787171045819973654991149949197959929860861228180021707316851924456205543665565810892674190059831330231436970914474774562714945620519144389785158908994181951348846017432506464163564960993784254153395406799101314760033445065193429592512349952020982932218524462341002102063435489318813316464511621736943938440710470694912336237680219746204595128959161800595216366237538296447335375818871952520026993102148328897083547184286493241191505953601668858941129790966909236941127851370202421135897091086763569884760099112291072056970636380417349019579768748054760104838790424708988260443926906673795975104689 ``` ### CERTainly not As mentioned in the previous challenge, PEM is just a nice wrapper above DER encoded ASN.1. In some cases you may come across DER files directly; for instance many Windows utilities prefer to work with DER files by default. However, other tools expect PEM format and have difficulty importing a DER file, so it's good to know how to convert one format to another. An SSL certificate is a crucial part of the modern web, binding a cryptographic key to details about an organisation. We'll cover more about these and PKI in the TLS category. Presented here is a DER-encoded x509 RSA certificate. Find the modulus of the certificate, giving your answer as a decimal. [2048b-rsa-example-cert.der](https://cryptohack.org/static/challenges/2048b-rsa-example-cert_3220bd92e30015fe4fbeb84a755e7ca5.der) ### Solution Đây là file DER-encoded x509 RSA certificate nên ta có thể sử dụng `RSA.import_key()` để đọc dữ liệu như RSA public key. ```python from Crypto.PublicKey import RSA with open('2048b-rsa-example-cert.der', 'rb') as f: public_key_der = f.read() public_key = RSA.import_key(public_key_der) print(public_key.n) ``` ```python 22825373692019530804306212864609512775374171823993708516509897631547513634635856375624003737068034549047677999310941837454378829351398302382629658264078775456838626207507725494030600516872852306191255492926495965536379271875310457319107936020730050476235278671528265817571433919561175665096171189758406136453987966255236963782666066962654678464950075923060327358691356632908606498231755963567382339010985222623205586923466405809217426670333410014429905146941652293366212903733630083016398810887356019977409467374742266276267137547021576874204809506045914964491063393800499167416471949021995447722415959979785959569497 ``` ### SSH Keys Extract the modulus n as a decimal integer from Bruce's SSH public key. [bruce_rsa.pub](https://cryptohack.org/static/challenges/bruce_rsa_6e7ecd53b443a97013397b1a1ea30e14.pub) #### Solution Tương tự câu trên, ta lại dùng `RSA.import_key()` để đọc dữ liệu RSA public key. ```python from Crypto.PublicKey import RSA f = open('bruce_rsa.pub', 'r') pubkey = RSA.import_key(f.read()) print(pubkey.n) ``` ```python 3931406272922523448436194599820093016241472658151801552845094518579507815990600459669259603645261532927611152984942840889898756532060894857045175300145765800633499005451738872081381267004069865557395638550041114206143085403607234109293286336393552756893984605214352988705258638979454736514997314223669075900783806715398880310695945945147755132919037973889075191785977797861557228678159538882153544717797100401096435062359474129755625453831882490603560134477043235433202708948615234536984715872113343812760102812323180391544496030163653046931414723851374554873036582282389904838597668286543337426581680817796038711228401443244655162199302352017964997866677317161014083116730535875521286631858102768961098851209400973899393964931605067856005410998631842673030901078008408649613538143799959803685041566964514489809211962984534322348394428010908984318940411698961150731204316670646676976361958828528229837610795843145048243492909 ``` ### Transparency In 2011 Comodo CA was compromised and the hacker was able to issue certificates for Gmail and other services. In 2016, Symantec was found to have issued over 150 certificates without the domain owner's knowledge, as well as 2400 certificates for domains that were never registered. Due to such events, together with the fact that fraudulent certificates can take a long time to be discovered, since 2018 `Certificate Transparency` has been enforced by Google Chrome. Every CA must publish all certificates that they issue to a log, which anyone can search. Attached is an RSA public key in PEM format. Find the subdomain of cryptohack.org which uses these parameters in its TLS certificate, and visit that subdomain to obtain the flag. [transparency.pem](https://cryptohack.org/static/challenges/transparency_afff0345c6f99bf80eab5895458d8eab.pem) #### Solution Đầu tiên ta thử tìm thêm thông tin về Certificate Transparency thì biết cert này sẽ lưu lại logs, ta có thể thực hiện tra cứu thông qua SHA256 của cert. ![image](https://hackmd.io/_uploads/H13tvdcJR.png) Thử tra cứu SHA256 tìm được trên trang crt.sh thì không thấy. Nhưng nó có hướng dẫn mình sang web https://search.censys.io/# ![image](https://hackmd.io/_uploads/BksBYd5yR.png) https://thetransparencyflagishere.cryptohack.org/ ``` crypto{thx_redpwn_for_inspiration} ```