diff --git a/_posts/inertia.md b/_posts/inertia.md
deleted file mode 100644
index 3ac1cd7..0000000
--- a/_posts/inertia.md
+++ /dev/null
@@ -1,20 +0,0 @@
-+++
-title = "cognitive inertia"
-description = "inertia"
-author = "mockingspectre"
-date = 2025-02-26
-[taxonomies]
-tags = ["cognition"]
-+++
-
-Staring at the void
-
-Cognitive inertia is the reason changing our habits can be difficult. If you want to overcome inertia you have to apply a force. I consider myself an eternal student, who is ready to learn anything, or so I thought. It happened but I had not noticed, I had stopped moving forward.
-
-## Metawork
-
-I will define this as the things we do before getting the "real" work doe. Its things like choosing the best IDE or text editor, setting up your coding environment, choosing the best note taking app, or even the 'best' operating system. They are the prerequisites of the actual work.
-
-I had been stuck on this loop, always trying to craft the perfect workflow. Setting up the best personalized linux distro, switching note taking apps, trying out multiple layouts, stylings and technologies for my blog, the list is endless.
-
-All of these metawork took more time thn the actual work; building, active learning and writing. Im going to stop all of these and start doing the important stuff.
diff --git a/content/posts/scriptctf2025/index.md b/content/posts/scriptctf2025/index.md
new file mode 100644
index 0000000..3d0fe8c
--- /dev/null
+++ b/content/posts/scriptctf2025/index.md
@@ -0,0 +1,779 @@
++++
+title = "ScriptCTF 2025 – Challenge Writeup"
+description = "ScriptCTF 2025 – Challenge Writeup"
+author = "mockingspectre"
+date = 2025-08-18
+[taxonomies]
+tags = ["ctf", "rev", "web", "forensics"]
++++
+
+# ScriptCTF 2025 – Challenge Writeup
+
+![][image1]
+Over the weekend, I participated in **ScriptCTF**, a capture-the-flag competition packed with diverse challenges spanning cryptography, forensics, reverse engineering, and web exploitation.
+
+Our team managed position \_\_\_\_\_\_ out of \_\_\_ teams with non zero points.
+
+In this write-up, I’ll walk through some of the problems I solved, breaking down my approach, the tools I used, and the reasoning behind each step. Rather than just dropping final answers, my goal is to document the problem-solving process in a way that’s reproducible and useful for others looking to sharpen their cybersecurity skills.
+
+# Challenge: Renderer
+
+![][image2]
+
+This is the first web challenge; it launches an instance, and the source code is provided for manual code review. There are three important files: two Jinja templates and a Python file.
+
+upload.html
+\`\`\`html
+\<\!DOCTYPE html\>
+\
+\
+ \Upload Image\
+\
+\
+ \
Upload Images\
+ \
This free to use website allows you to render your images\!\
+\
+\
+\`\`\`
+
+\`[app.py](http://app.py)\`
+
+\`\`\`python
+from flask import Flask, request, redirect, render\_template, make\_response, url\_for
+app \= Flask(\_\_name\_\_)
+from hashlib import sha256
+import os
+def allowed(name):
+ if name.split('.')\[1\] in \['jpg','jpeg','png','svg'\]:
+ return True
+ return False
+
+@app.route('/',methods=\['GET','POST'\])
+def upload():
+ if request.method \== 'POST':
+ if 'file' not in request.files:
+ return redirect(request.url)
+ file \= request.files\['file'\]
+ if file.filename \== '':
+ return redirect(request.url)
+ if file and allowed(file.filename):
+ filename \= file.filename
+ hash \= sha256(os.urandom(32)).hexdigest()
+ filepath \= f'./static/uploads/{hash}.{filename.split(".")\[1\]}'
+ file.save(filepath)
+ return redirect(f'/render/{hash}.{filename.split(".")\[1\]}')
+ return render\_template('upload.html')
+
+@app.route('/render/\')
+def render(filename):
+ return render\_template('display.html', filename=filename)
+
+@app.route('/developer')
+def developer():
+ cookie \= request.cookies.get("developer\_secret\_cookie")
+ correct \= open('./static/uploads/secrets/secret\_cookie.txt').read()
+ if correct \== '':
+ c \= open('./static/uploads/secrets/secret\_cookie.txt','w')
+ c.write(sha256(os.urandom(16)).hexdigest())
+ c.close()
+ correct \= open('./static/uploads/secrets/secret\_cookie.txt').read()
+ if cookie \== correct:
+ c \= open('./static/uploads/secrets/secret\_cookie.txt','w')
+ c.write(sha256(os.urandom(16)).hexdigest())
+ c.close()
+ return f"Welcome\! There is currently 1 unread message: {open('flag.txt').read()}"
+ else:
+ return "You are not a developer\!"
+
+if \_\_name\_\_ \== '\_\_main\_\_':
+ app.run(host='0.0.0.0', port=1337)
+\`\`\`
+
+From the files, we can see that this is an app built using Flask. What the app does:
+
+`/` — Upload endpoint:
+
+* Accepts `jpg`, `jpeg`, `png`, `svg` files.
+
+* Saves them under `./static/uploads/.`.
+
+* Redirects to `/render/`.
+
+`/render/` — Renders the uploaded image using `display.html`.
+
+`/developer` — Protected route:
+
+* Checks a cookie `developer_secret_cookie` against `secret_cookie.txt`.
+
+* If it matches, it reveals `flag.txt`.
+
+`secret_cookie.txt` is generated if empty and is overwritten after a successful visit.
+
+Key Observations
+
+1. File upload: Only the extension is checked; there is no content verification. So you can upload anything with .jpg, .png, etc.
+
+2. Render template: The render() route calls render\_template('display.html', filename=filename).
+
+3. Secrets: The /developer route requires knowing secret\_cookie.txt. We need a way to leak it.
+
+Navigating to the developer endpoint without the cookie returns this request.
+\`\`\`
+HTTP/1.1 200 OK
+Server: Werkzeug/3.1.3 Python/3.10.16
+Date: Sun, 17 Aug 2025 11:51:49 GMT
+Content-Type: text/html; charset=utf-8
+Content-Length: 24
+Connection: close
+
+You are not a developer\!
+\`\`\`
+Now I tried some path traversal techniques, but I couldn't reach the cookie. I turned my focus on how the uploaded images were being rendered and saw that it was an inline iframe. Hmm… interesting, what if I could get code execution on this? I thought of uploading a malicious SVG.
+Here is an innocent-looking SVG
+
+\`\`\`
+\
+\`\`\`
+
+And…
+![][image3]
+I didn't think that through. I can't make that request without the cookie. Another approach I tried was Local File Inclusion(LFI) using the SVG. Here is another not-so-evil one:
+
+\`\`\`
+\
+\`\`\`
+The browser shows it as a broken image, but on opening it on another tab, I was able to leak the cookie \`5eb7b76fbb08895de572fbe6028a4ee4abe3663641416deb5b889e0127920c6e\`. I copied and pasted the direct URL on another browser tab, and I got straight to it. I might have over-engineered something so simple, but anyway, Do Hard Things\!\!
+Retrieving the flag
+\`\`\`
+$ curl \-b "developer\_secret\_cookie=5eb7b76fbb08895de572fbe6028a4ee4abe3663641416deb5b889e0127920c6e" http://play.scriptsorcerers.xyz:10257/developer
+
+Welcome\! There is currently 1 unread message: scriptCTF{my\_c00k135\_4r3\_n0t\_s4f3\!\_601871f7aad5}
+\`\`\`
+
+Flag: `scriptCTF{my_c00k135_4r3_n0t_s4f3!_601871f7aad5}`
+
+# Challenge: Div
+
+![][image4]
+Here are the contents of the [chall.py](http://chall.py)
+\`\`\`
+import os
+import decimal
+decimal.getcontext().prec \= 50
+
+secret \= int(os.urandom(16).hex(),16)
+num \= input('Enter a number: ')
+
+if 'e' in num.lower():
+ print("Nice try...")
+ exit(0)
+
+if len(num) \>= 10:
+ print('Number too long...')
+ exit(0)
+
+fl\_num \= decimal.Decimal(num)
+div \= secret / fl\_num
+
+if div \== 0:
+ print(open('flag.txt').read().strip())
+else:
+ print('Try again...')
+\`\`\`
+
+Let’s break it down:
+
+1. The server picks a **secret** — a random 128-bit integer (`os.urandom(16)` → 32 hex chars → huge number).
+
+2. You input a number `num`.
+
+3. If your input contains `'e'` or `'E'` (scientific notation), you get blocked.
+
+4. If your input is ≥ 10 characters, you get blocked.
+
+5. It converts `num` to a `decimal.Decimal` with precision 50\.
+
+6. It computes `div = secret / fl_num`.
+
+7. If `div == 0`, you get the flag.
+
+**Key observation**
+
+* `secret` is positive and huge (on the order of `2**128`).
+
+* Normally, `secret / something` won’t be 0\.
+
+* In Python `decimal.Decimal`, `div == 0` **only if** the result is *exactly* 0\. Decimal doesn’t overflow or underflow like float — it has arbitrary precision (set to 50).
+
+So how do we get exactly zero?
+
+* Decimal division only returns `0` if the numerator is `0` OR if the denominator is so huge that the quotient rounds down to 0 at the given precision.
+
+* Precision is **50 significant digits**. That means if the result is smaller than `10^(-50)`, it will round to 0\.
+
+We want
+
+`secret / fl_num < 10^-50`.
+
+ `fl_num > secret × 10^50`
+
+Since
+
+`secret` ≈ `2^128` ≈ `3.4 × 10^38`,
+
+we need
+
+\`fl\_num \> (3.4 × 10^38) × 10^50 \= 3.4 × 10^88\`
+
+But there’s a catch
+We can’t use exponent notation (e), and the input length must be \< 10 characters.
+
+That means we can’t type a literal 100000... with 89 zeros, it’s too long.
+But in Decimal, you can input a decimal point and make something big by making it a very small number and dividing 1 by it.
+
+This is about **NaN / Infinity** in `decimal.Decimal`. If `fl_num` is `'Infinity'` (allowed, length 8), `secret / Infinity`
+
+\`\`\`
+nc play.scriptsorcerers.xyz 10456
+
+Enter a number: Infinity
+scriptCTF{70\_1nf1n17y\_4nd\_b3y0nd\_20e422d293fc}
+\`\`\`
+Flag: \`scriptCTF{70\_1nf1n17y\_4nd\_b3y0nd\_20e422d293fc}\`
+
+Some context
+Python’s decimal.Decimal module implements IEEE 754 decimal floating-point arithmetic.
+It accepts strings like:
+
+"Infinity" or "inf" → positive infinity
+
+"-Infinity" → negative infinity
+
+"NaN" → not-a-number
+
+These are special constants, not parsed as normal numbers.
+
+Under IEEE 754 rules:
+
+- finite\_number / Infinity \= 0 exactly
+
+- finite\_number / \-Infinity \= \-0 (also treated as zero)
+
+Infinity represents a number so large that any finite numerator divided by it tends towards 0 exactly, with no rounding error.
+
+# Challenge: Emoji
+
+![][image5]
+Out.txt has some symbols.
+\`\`\`
+🁳🁣🁲🁩🁰🁴🁃🁔🁆🁻🀳🁭🀰🁪🀱🁟🀳🁮🁣🀰🁤🀱🁮🁧🁟🀱🁳🁟🁷🀳🀱🁲🁤🁟🀴🁮🁤🁟🁦🁵🁮🀡🀱🁥🀴🀶🁤🁽
+\`\`\`
+The symbols are Unicode Domino Tiles (in the U+1F030–U+1F093 range). If you subtract 0x1F000 (the start of the Mahjong/Domino emoji area) from each character’s code point, you get plain ASCII bytes. You can learn more about Unicode here.
+
+- [https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/](https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/)
+- [https://en.wikipedia.org/wiki/Dominoes\#Dominoes\_in\_Unicode:\~:text=%5B38%5D-,Dominoes%20in%20Unicode,-%5Bedit%5D](https://en.wikipedia.org/wiki/Dominoes#Dominoes_in_Unicode:~:text=%5B38%5D-,Dominoes%20in%20Unicode,-%5Bedit%5D)
+- https://www.reedbeta.com/blog/programmers-intro-to-unicode/
+
+
+
+Here is a Python script for that(old habits die hard)
+\`\`\`
+s \= "🁳🁣🁲🁩🁰🁴🁃🁔🁆🁻🀳🁭🀰🁪🀱🁟🀳🁮🁣🀰🁤🀱🁮🁧🁟🀱🁳🁟🁷🀳🀱🁲🁤🁟🀴🁮🁤🁟🁦🁵🁮🀡🀱🁥🀴🀶🁤🁽"
+print(''.join(chr(ord(ch) \- 0x1F000) for ch in s))
+\`\`\`
+
+\`\`\`
+$ python3 **solve.py**
+scriptCTF{3m0j1\_3nc0d1ng\_1s\_w31rd\_4nd\_fun\!1e46d}
+\`\`\`
+Flag : `scriptCTF{3m0j1_3nc0d1ng_1s_w31rd_4nd_fun!1e46d}`
+
+# Challenge: Enchant
+
+![][image6]
+After some Google search, I found out that’s the **Standard Galactic Alphabet**, the glyphs used by Minecraft’s enchantment table. The enchantment-table glyphs map one-to-one to letters in the Standard Galactic Alphabet (SGA). I used the SGA ↔ Latin mapping to translate each symbol into its English letter at [https://www.dcode.fr/standard-galactic-alphabet](https://www.dcode.fr/standard-galactic-alphabet). The result is MINECRAFTISFUN.
+
+Flag: scriptCTF{MINECRAFTISFUN}
+
+Challenge: diskchal
+![][image7]
+This was a forensics challenge; we were given a disk image, probably to recover some files, as the challenge description suggests.
+
+\`\`\`
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/diskchal**$ file **stick.img**
+stick.img: DOS/MBR boot sector, code offset 0x58+2, OEM-ID "mkfs.fat", sectors 49152 (volumes \<=32 MB), Media descriptor 0xf8, sectors/track 32, heads 4, FAT (32 bit), sectors/FAT 378, reserved 0x1, serial num
+ber 0x8caae860, unlabeled
+\`\`\`
+
+The file is a FAT32 filesystem image created with `mkfs.fat`.I try to mount the image and see what's inside.
+
+\`\`\`
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/diskchal**$ sudo mount **stick.img** **mnt/**
+
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/diskchal**$ ls **mnt**
+**notes.txt** **random\_thoughts.txt**
+
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/diskchal**$ cat **\*** **mnt/**
+cat: mnt: Is a directory
+�X�mkfs.fat �� z�)\`誌NO NAME FAT32 �w|�"�t
+ V^2�����This is not a bootable disk. Please insert a bootable floppy and
+press any key to try again ...
+U�RRaArrAa��U��X�mkfs.fat �� z�)\`誌NO NAME FAT32 �w|�"�t
+ V���^��2�����This is not a bootable disk. Please insert a bootable floppy and
+press any key to try again ...
+U�RRaArrAa��U�������������������������������Anotes�.txt������NOTES TXT Rk��Z\[k��ZLBts.tx\** hash.txt
+
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/justsome-avocado**$ john \--format=PKZIP **hash.txt** \--wordlist=/usr/share/wordlists/rockyou.txt
+
+Using default input encoding: UTF-8
+Loaded 1 password hash (PKZIP \[32/64\])
+Will run 4 OpenMP threads
+Press 'q' or Ctrl-C to abort, almost any other key for status
+impassive3428 (justsomezip.zip)
+1g 0:00:00:01 DONE (2025-08-17 17:16) 0.7633g/s 5609Kp/s 5609Kc/s 5609KC/s in4nd0keren..imissdesi
+Use the "--show" option to display all of the cracked passwords reliably
+Session completed.
+\`\`\`
+After a few seconds, the password is revealed to be \`impassive3428\`. Inside the zip were two files with the same name as before
+\`\`\`
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/justsome-avocado/justsomezip**$ tree
+**.**
+├── **justsomezip.zip**
+└── staticnoise.wav
+
+1 directory, 2 files
+
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/justsome-avocado/justsomezip**$ file **\***
+justsomezip.zip: Zip archive data, made by v3.0 UNIX, extract using at least v1.0, last modified Jun 24 2025 19:12:42, uncompressed size 28, method=store
+staticnoise.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, stereo 22050 Hz
+\`\`\`
+
+I tried brute-forcing the password again, but there were no positive results, so I shifted my focus onto the WAV file. Running exiftool on it showed a telling comment. The password couldn't be brute-forced
+
+\`\`\`
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/justsome-avocado/justsomezip**$ exiftool **staticnoise.wav**
+ExifTool Version Number : 13.25
+File Name : staticnoise.wav
+Directory : .
+File Size : 438 kB
+File Modification Date/Time : 2025:06:25 13:38:40+03:00
+File Access Date/Time : 2025:08:17 17:18:23+03:00
+File Inode Change Date/Time : 2025:08:17 17:18:17+03:00
+File Permissions : \-rw-r--r--
+File Type : WAV
+File Type Extension : wav
+MIME Type : audio/x-wav
+Encoding : Microsoft PCM
+Num Channels : 2
+Sample Rate : 22050
+Avg Bytes Per Sec : 88200
+Bits Per Sample : 16
+Comment : What if my password isn't on rockyou.txt
+Software : Lavf61.7.100
+Duration : 4.96 s
+
+\`\`\`
+
+I opened the file in Sonic Visualizer and applied a spectrogram view. Here is what shows
+![][image11]
+
+It looks like some embedded text, but it's clipped. I redid the same process in Audacity, and this is what it shows.
+
+![][image12]
+
+I can make out the first three characters, d41, and the fifth \`3\`. We can use John's mask mode to generate the possible combinations.
+
+\`\`
+john \--mask='d41?1?1?1?1?1' \--1='?l?d' \--format=PKZIP hash.txt
+\`\`\`
+
+* d41 \= known prefix
+* ?1?1?1?1?1 \= 5 unknown characters
+* \--1='?l?d' \= defines ?1 as “lowercase letters or digits”
+* \--format=PKZIP \= tells John it’s a ZIP hash
+
+\`\`\`
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/justsome-avocado/justsomezip**$ john \--mask='d41?1?1?1?1?1' \--1='?l?d' \--format=PKZIP **hash.txt**
+
+Using default input encoding: UTF-8
+Loaded 1 password hash (PKZIP \[32/64\])
+Will run 4 OpenMP threads
+Press 'q' or Ctrl-C to abort, almost any other key for status
+d41v3ron (justsomezip.zip/flag.txt)
+1g 0:00:00:00 DONE (2025-08-17 21:23) 1.388g/s 9545Kp/s 9545Kc/s 9545KC/s d41v7non..d41oddon
+Use the "--show" option to display all of the cracked passwords reliably
+Session completed.
+
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/justsome-avocado/justsomezip**$ unzip **justsomezip.zip**
+Archive: justsomezip.zip
+\[justsomezip.zip\] flag.txt password:
+extracting: flag.txt
+
+**mockingspectre@kali**:**\~/ctf/scriptctf2025/forensics/justsome-avocado/justsomezip**$ cat **flag.txt**
+scriptCTF{1\_l0ve\_d41\_v3r0n}
+\`\`\`
+
+Flag: \`scriptCTF{1\_l0ve\_d41\_v3r0n}\`
+
+# Challenge: RSA-1
+
+![][image13]
+
+The attachment out.txt has
+\`\`\`
+out.txt has: n1 \= 156503881374173899106040027210320626006530930815116631795516553916547375688556673985142242828597628615920973708595994675661662789752600109906259326160805121029243681236938272723595463141696217880136400102526509149966767717309801293569923237158596968679754520209177602882862180528522927242280121868961697240587 c1 \= 77845730447898247683281609913423107803974192483879771538601656664815266655476695261695401337124553851404038028413156487834500306455909128563474382527072827288203275942719998719612346322196694263967769165807133288612193509523277795556658877046100866328789163922952483990512216199556692553605487824176112568965 n2 \= 81176790394812943895417667822424503891538103661290067749746811244149927293880771403600643202454602366489650358459283710738177024118857784526124643798095463427793912529729517724613501628957072457149015941596656959113353794192041220905793823162933257702459236541137457227898063370534472564804125139395000655909 c2 \= 40787486105407063933087059717827107329565540104154871338902977389136976706405321232356479461501507502072366720712449240185342528262578445532244098369654742284814175079411915848114327880144883620517336793165329893295685773515696260299308407612535992098605156822281687718904414533480149775329948085800726089284 n3 \= 140612513823906625290578950857303904693579488575072876654320011261621692347864140784716666929156719735696270348892475443744858844360080415632704363751274666498790051438616664967359811895773995052063222050631573888071188619609300034534118393135291537302821893141204544943440866238800133993600817014789308510399 c3 \= 100744134973371882529524399965586539315832009564780881084353677824875367744381226140488591354751113977457961062275480984708865578896869353244823264759044617432862876208706282555040444253921290103354489356742706959370396360754029015494871561563778937571686573716714202098622688982817598258563381656498389039630 e \= 3
+\`\`\`
+
+ this is the classic low-exponent (e \= 3\) broadcast attack. To crack it:
+
+1. Use the three ciphertexts c1,c2,c3c\_1,c\_2,c\_3c1,c2,c3 and moduli n1,n2,n3n\_1,n\_2,n\_3n1,n2,n3.
+
+2. Combine them with the Chinese Remainder Theorem to reconstruct M=m3 mod NM \= m^3 \\bmod NM=m3modN where N=n1n2n3N \= n\_1 n\_2 n\_3N=n1n2n3. Because the original message mmm is smaller than each modulus and m3\
+
+[image2]:
+
+[image3]:
+
+[image4]:
+
+[image5]:
+
+[image6]:
+
+[image7]:
+
+[image8]:
+
+[image9]:
+
+[image10]:
+
+[image11]:
+
+[image12]:
+
+[image13]:
+
+[image14]:
+
+[image15]:
\ No newline at end of file