# 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}
```