Skip to main content
  1. Posts/

Squid Game CTF - Hc0n 2023

·3123 words·15 mins
Defense Evasion kraken webshell redteam ctf

Home Page

Presentation #

Squid Game is a CTF created for the Hc0n 2023 conference. The scenario has been based on the Netflix series: The Squid Game.

The characteristics of this CTF are the following:

  • It consists of three Boot2Root style challenges (get maximum privileges).
  • The web service is used as the Initial Access path.
  • The three machines have been configured to avoid command execution and do not have Internet access.
  • The objective is to perform a post-exploitation through the webshell and achieve privilege escalation. It will not be necessary to perform any additional web exploit, since the challenges are focused on post-exploitation and therefore the initial access is provided.
  • Privilege escalations are fairly straightforward, however, the difficulty lies in the conditions that make exploitation difficult.

The following will show the proposed solution for each of the challenges using Kraken, the tool I developed and presented at Hc0n 2023.


Kraken, a modular multi-language webshell coded by @secu_x11


After this… Let’s get started!

Challenge 1 - Red Light, Green Light #

When we visit the link of the first challenge we find the following website:

In the robots.txt of the site we can discover a non-indexed endpoint: /upload.php.

PHP Webshell Deployment #

Upon visiting this endpoint, we found what appears to be an arbitrary file upload:

To confirm the vulnerability, you can upload an Standard, PHP Kraken agent.

After uploading it, the page returns the remote path where the file has been uploaded. After validating that it is accessible, we proceed to generate a connection profile to connect to the Kraken agent.

You can generate connection profiles using a utility that Kraken offers. This is called req2profile and allows you to transform Burpsuite requests to Kraken-compatible Connection Profiles.

After defining the JSON fields as shown above, we can connect to the agent:

System reconnaissance #

With the implant deployed, and the client connected, we can start with the local reconnaissance of the computer.

First of all, we can verify that it is not possible to execute system commands through the webshell itself:

This is because, the typical PHP functions for executing commands, have been disabled via the PHP configuration (disabled_functions).

It is possible to obtain the list of disabled functions through Kraken using the webinfo module.

However, this configuration does not prevent us from moving through the file system using native functionalities provided by PHP.

If we look in the /opt directory, we can find a squid-control folder containing several files and directories of interest.

Analyzing the file contents and context information we can identify a Wildcard Poisoning1 vulnerability in the script /opt/squid-control/

Wildcard Poisoning Exploitation #

Wildcard Poisoning occurs because the script is using a wildcard (*) as an argument to the tar command (indicating that all files in the /var/www/html/files directory should be compressed).

This command presents a vulnerability because the wildcard allows the name of a file to be taken as an argument of the tar command itself.

And precisely, the tar command contains a number of arguments that may lead to arbitrary code execution2.

However, to confirm the elevation of privileges, we can look at the /opt/squid-control/tmp folder where we can see how, every minute, a file is created with the format: <date>.tar.gz. This contains the files in the /var/www/html/files directory.

Moreover, the owner of these files is the root user. Therefore, it is possible that there is a cronjob running the /opt/squid-control/ script every minute.

To confirm this theory, we can use the Kraken module pspy

This module lists the Linux processes from the information contained under the file system: /proc. By listing this path, we can discover a series of subdirectories with numerical values. These correspond to the existing PIDs on the machine, and are virtual files containing the information of each process.

You can find more information about this file system here.3

The module obtains the list of processes in each interval (-i), during the indicated seconds (-d). In this period it detects new processes, processes that stop and displays them in an intuitive format.

In this way we can confirm the execution of the /opt/squid-control/ script through a cronjob executed as root (otherwise it would not have been possible since the cronjobs of other unprivileged users cannot be listed).

Before proceeding with the exploitation, we list the ports in use on the victim machine. For this we can rely on the netstat module which obtains the network information from the virtual files under /proc/net/

Thanks to this module we can identify the existence of a possible SSH service listening on the address

With the information gathered we can set up the following privilege elevation vector:

  1. A script is uploaded to the machine that, when running, adds an SSH public key to the /root/.ssh/authorized_keys file. This will enable public key based authentication4 as the root user.

mkdir -p /root/.ssh/
echo -n "ssh-rsa AAAAB3...JMClw==" > /root/.ssh/authorized_keys
  1. Next, we create the files that produce the wildcard poisoning exploitation and execute the script from the previous step.

SSH access via HTTP Tunneling #

After a few seconds, we will proceed to upload a tunneling utility that will allow us to communicate with the internal services of the machine. For this case, I will use pivotnacci.


A tool to make socks connections through HTTP agents


I upload the PHP agent to the /var/www/html/files directory using Kraken’s upload module.

This module allows you to upload local files in chunks, specifying the delay between requests (-d) as well as the size of each chunk (-c). And, in case the transfer is interrupted/cut off, it can be resumed by specifying the last transmitted seek (-s). This is a good option when uploading large files.

With the tunneling utility deployed, we can use the SSH private key to authenticate against the local service of the victim machine and get a console as root.

Finally, through this console, we have all the privileges and can obtain the challenge flag.

Before finishing we delete the files that we have used in the elevation of privileges.

LD_PRELOAD and alternative flag #

However, the challenge does not end here. There is the possibility of introducing an “alternative” flag that escapes from the main path of the challenge.

In case you have tried to evade the configuration related to the disabled_functions, it is possible that you have tried to do it using some tool like Chankro (which is well known in this kind of post exploits).


Herramienta para evadir disable_functions y open_basedir


However, in the disabled functions are those that allow us to perform the evasion with this tool. Although, if we look at the system variables defined for our user www-data we can discover a predefined value in the variable LD_PRELOAD.

This variable points to a library located in /usr/local/lib/ Using the download module of Kraken we can download it.

At this point, we could reverse engineer and analyze its operation, although it is possible to recover the alternative flag from the strings in the data section of the library.

Even though I have obtained the flag, I am going to explain the operation and purpose of this library:

Firstly, it is an adaptation of the code of the zap-args of TheHackersChoice.


Various tips & tricks


The zap-args.c code is a defense evasion utility, which focuses on hiding the arguments passed to a command or binary. It uses the LD_PRELOAD variable to intercept the call to main from the execution of your command and empties the reference to the argument array passed to it. So, when doing an ps, the kernel is not able to retrieve the arguments passed to the program, since the reference is empty, and simply displays the binary executed.

In my case, I have used the same idea but not to “hide” the arguments, but to intercept them as an EDR would do. This way you can intercept those commands executed by the www-data user and, in case of calling a shell, block them.

The code of is as follows:

 * gcc -Wall -O2 -fpic -shared -o hook.c -ldl
#define _GNU_SOURCE 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <dlfcn.h>
#include <pwd.h>
#include <sys/types.h>

typedef int (*pfi)(int, char **, char **);
static pfi real_main;

int check_args(int argc, char** argv)
    if (argc < 1)
        return 0;
    // Checking for shell execution
    if (strcmp(argv[0], "sh") == 0)
        return 1;
    else if (strcmp(argv[0], "bash") == 0)
        return 1;
    else if (strcmp(argv[0], "rbash") == 0)
        return 1;
    else if (strcmp(argv[0], "dash") == 0)
        return 1;
    return 0;

static int mymain(int argc, char** argv, char** env)
    struct passwd *p = getpwuid(getuid());

    if (strcmp(p->pw_name, "www-data") == 0)
        if (check_args(argc, argv) == 1)
            char *alt_flag = "squid-game{Byp4ssAllTh3Th1ngS!}";
            printf("Nice try! But it's not this way. Although, here is your alternative fl4g: %s", alt_flag);
    return real_main(argc, argv, env);

int __libc_start_main(pfi main, int argc,
                      char **ubp_av, void (*init) (void),
                      void (*fini)(void),
                      void (*rtld_fini)(void), void (*stack_end))
    static int (*real___libc_start_main)() = NULL;

    if (!real___libc_start_main)
        char *error;
        real___libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main");
        if ((error = dlerror()) != NULL)
            fprintf(stderr, "%s\n", error);
    real_main = main;
    return real___libc_start_main(mymain, argc, ubp_av, init, fini, rtld_fini, stack_end);

Obviously, it is an insult to expect this to serve as a “block” against someone who has evaded the proposed defenses. However, it is simply a reward to show the player that he has done well, but that it is not the way.

So much for the first challenge.

Challenge 2 - Dalgona Candy #

Accessing the url of the challenge we can find the following view:

By inspecting the page code we discovered a hidden /upload.aspx path:

ASPX Webshell Deployment #

When visiting it we can see, as in the first challenge, an arbitrary file upload.

In this case, we proceed to upload a Kraken agent as ASPX.

We generate the connection profile specifying the path of the newly deployed agent:

And finally we connect to the webshell using Kraken.

Local Reconnaissance #

First, we check that there is an App Locker installed on the machine that prevents us from executing commands with the current Application Pool Identity (WINWS02\webusr).

At this point, we could start doing a exhaustive reconnaissance looking for vulnerable services, programs in use, files with credentials, etc. But in this case, exploitation will be much simpler.

First we check the context of our user, and also his privileges. Using the whoami module is quite easy.

As you can see, the SeImpersonate privilege is available, which we can abuse to get SYSTEM.

Privilege Elevation with SeImpersonate Privilege #

To do this, I am going to use a modified version of the BadPotato program.

BadPotato uses the Windows print service (spoolss) to exploit a Forced Authentication5. This forced authentication occurs through the RPC call: RpcRemoteFindFirstPrinterChangeNotificationEx(), which generates a notification object that monitors changes to a print object. This is used to force the print service to connect to a NamedPipe that we have created and steal the access token from it. As the user running the print service is the system account, we can use his token to elevate privileges.


Windows 权限提升 BadPotato


In the modification I remove all the part of the process creation that BadPotato uses to run as SYSTEM.

On the other hand, by removing the CloseHandle() from the duplicate token reference, I trigger the leak. This way, the token is leaked in my own process (w3wp.exe) and I can use it later from the webshell context.

In addition to getting privilege elevation, I maintain the privileged context from the token reference. What could be considered as a Privilege Elevation + Persistence.

Through Kraken’s execute_assembly module, I can load the NET Assembly of the modified version of BadPotato and get the leak of the SYSTEM token.

With the set_token module, I can use the token reference to make the impersonation of the system account effective. Using an impersonation token derived from the filtering, I can get all the modules that Kraken executes to do so under the SYSTEM security context:

After this, it has been possible to elevate privileges and a “pseudo-console” is available as the SYSTEM user. So, it is possible to read the desktop flag of the Local Administrator of the machine and complete the challenge.

SAM, SECURITY and SYSTEM registry extraction #

However, in a more realistic scenario, proving privileges would not be enough. It would be necessary to perform some kind of post-exploitation to compromise the machine and/or obtain credentials.

To demonstrate the possibility of performing this task with Kraken, we will use the secretsdump module that will allow us to extract the SAM, SECURITY and SYSTEM from the machine registry.

The secretsdump module combines impersonation with the use of Transacted Files to achieve that, the call to NtSaveKey() saves the content of the registry key in an “in memory” file. In this way we can access its content, but it is not written to disk, so we can exfiltrate it without the need to complete the transaction.

At the moment the module writes the files to our local machine, we can use the utility: secretsdump of Impacket to obtain the local accounts of the machine.


Impacket is a collection of Python classes for working with network protocols.


With the information obtained in this process, it is possible to use it to get an interactive session on the compromised machine (independent of the webshell).

And with this, the second challenge is completed.

Challenge 3 - The Glass Tile #

This challenge is intended to demonstrate the potential of using Windows tokens during the web post-exploitation process. The idea came from research done by my colleague Kurosh Dabag Escalante: One shell to HANDLE them all.6

So, let’s start by visiting the url of the challenge:

Again we can see in the source code some hidden paths:

When visiting the /admin endpoint we find a simple static page. There doesn’t seem to be much more to it.

ASPX Webshell Deployment #

On the other hand, if we visit the /upload.aspx path we again encounter an arbitrary file upload.

So we are back to uploading a Kraken ASPX agent as in the previous challenge.

We generate a connection profile and, again, connect to the agent.

Local reconnaissance and token leakage #

We advise the same policies of the App Locker that prevent the execution of commands:

However, when listing the existing tokens in our process, we discovered one under the security context of the user WINWS03\square.

When impersonating this user we can verify that it is a member of the local Administrators group of the machine, and that the token is in high integrity.

The explanation to this is that, there is a Virtual Directory configured in the IIS. This virtual directory points to the local path: C:/Users/square/adminsite/. In order for the Application Pool Identity to access this directory, it needs a pair of valid credentials. For this case, ones have been configured in ClearText of the user WINWS03\square.

The endpoint that manages this virtual directory is /admin, therefore, when accessing this endpoint, the IIS authenticates as the WINWS03\square user to access, which results in the leak of a primary token as this user.

Elevation of Privileges with nested impersonations #

Through the first impersonation we managed to elevate privileges from WINWS03\webusr to WINWS03\square (local admin). However, to get the highest number of privileges on the computer, it is necessary to escalate to SYSTEM.

To do this, as we have administrator privileges and are in high integrity, we proceed to search for a process running as SYSTEM. To do this we use the ps module of Kraken and, among the different processes, we identify a candidate: winlogon.exe.

It is well known that the winlogon process runs on the system account and, in addition to this, it is possible to duplicate its main token and use it for impersonation.

Using Kraken’s dup_token module, we can duplicate the winlogon token and get one as SYSTEM in our current process.

When using this token and impersonating the system account, we go to the directory C:/Users/Administrator/Desktop where the flag is located. And, if we try to read the flag, we get a “permission denied” error.

This is because there is an ACL configured in the squid-flag.txt file so that it can only be accessed by its owner: WINWS03\Administrator.

In order to set this ACL and remove the rest, the " inherited permissions “ had to be removed from the file.

Given this configuration, the possibility of impersonating the WINWS03\Administrator user is suggested. In order to do this, we check the list of processes again, and find a promising one:

The process with PID: 3132, corresponds to a Procmon64, which is running under the directory C:/Users/Administrator/Downloads/ProcessMonitor, which means that it is possible that this user has launched the process in his logon session.

The premise is confirmed through the duplication of the process token, and the impersonation by making use of it. In this context, the challenge flag can finally be accessed:

Extraction of secrets through the IIS Administration Module #

And finally, to complete the post-exploitation, having Administrator and High Integrity privileges, it is possible to extract the secrets configured in the IIS using the library: Microsoft.Web.Administration (used for the administration of the web server).

Through this functionality, it is possible to retrieve the plaintext credentials configured for any AppPool, VirtualDirectory or AppPoolIdentity. To do this, just use the Kraken module dump_iis_secrets

To develop the dump_iis_secrets module, I used the idea described by Grzegorz Tworek in one of his Tweets7 that talks about the possibility of extracting these credentials using the appcmd.exe binary.

Conclusions #

In conclusion, the potential and comfort in using Kraken as a web post-exploitation tool is demonstrated. Different exploits in different scenarios have been covered.

Finally, you can find the code of the challenges, as well as the commands used, at the following link.

Or, you can download the OVAs of the challenges from Mega.

Hope you liked it, and see you in the next post!