SCTF Misc100 WriteUp

Reading time ~1 minute

似乎每次比赛都会有一道游戏题,这次SCTF的游戏题就是这道了,话说着实没想明白为什么这题算是Misc……

题目描述就一句话:

简单的贪吃蛇,吃到30分它就告诉你flag!但是要怎么控制它呢?

首先将程序download下来,是一个后缀名为exe的程序,果断就给扔XP虚拟机里了,一运行就看到一个控制台窗口上一个光标跳来跳去,完全看不懂,说好的贪吃蛇呢……

然后往IDA里面扔的时候,却被自动识别为类型为ELF,当时就惊呆了……

然后放Unbuntu里跑,总算是正常看到了贪吃蛇,不过果不其然不知道怎么能够控制。

然后就只能规规矩矩看程序了,很明显程序是加了个UPX的壳(PEiD查的),于是马上aptget了一个upx,然后upx -d搞定。

看程序的时候,从start一路跟下去,会发现程序进到了如下一段代码中:

.text:08048C40
.text:08048C40 ; Segment type: Pure code
.text:08048C40 ; Segment permissions: Read/Execute
.text:08048C40 _text segment para public 'CODE' use32
.text:08048C40 assume cs:_text
.text:08048C40 ;org 8048C40h
.text:08048C40 assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing
.text:08048C40
.text:08048C40
.text:08048C40 ; Attributes: noreturn bp-based frame
.text:08048C40
.text:08048C40 sub_8048C40 proc near
.text:08048C40 lea     ecx, [esp+4]
.text:08048C44 and     esp, 0FFFFFFF0h
.text:08048C47 push    dword ptr [ecx-4]
.text:08048C4A push    ebp
.text:08048C4B mov     ebp, esp
.text:08048C4D push    ecx
.text:08048C4E sub     esp, 4
.text:08048C51 call    _initscr
.text:08048C56 call    sub_8048EA0
.text:08048C5B sub     esp, 8
.text:08048C5E push    offset handler  ; handler
.text:08048C63 push    0Eh             ; sig
.text:08048C65 call    _signal
.text:08048C6A pop     eax
.text:08048C6B pop     edx
.text:08048C6C push    offset sub_8048E10 ; handler
.text:08048C71 push    38h             ; sig
.text:08048C73 call    _signal
.text:08048C78 pop     ecx
.text:08048C79 pop     eax
.text:08048C7A push    offset sub_8048E70 ; handler
.text:08048C7F push    32h             ; sig
.text:08048C81 call    _signal
.text:08048C86 pop     eax
.text:08048C87 pop     edx
.text:08048C88 push    offset nullsub_1 ; handler
.text:08048C8D push    5               ; sig
.text:08048C8F call    _signal
.text:08048C94 pop     ecx
.text:08048C95 pop     eax
.text:08048C96 push    offset sub_8048E10 ; handler
.text:08048C9B push    0Ah             ; sig
.text:08048C9D call    _signal
.text:08048CA2 pop     eax
.text:08048CA3 pop     edx
.text:08048CA4 push    offset sub_8048E70 ; handler
.text:08048CA9 push    0Ch             ; sig
.text:08048CAB call    _signal
.text:08048CB0 pop     ecx
.text:08048CB1 pop     eax
.text:08048CB2 push    offset sub_8048DE0 ; handler
.text:08048CB7 push    34h             ; sig
.text:08048CB9 call    _signal
.text:08048CBE pop     eax
.text:08048CBF pop     edx
.text:08048CC0 push    offset sub_8048E40 ; handler
.text:08048CC5 push    36h             ; sig
.text:08048CC7 call    _signal
.text:08048CCC add     esp, 10h
.text:08048CCF call    sub_80492C0
.text:08048CCF sub_8048C40 endp
.text:08048CCF

可以看到基本都是在发信号来完成整个程序,那么程序的关键肯定就在信号处理函数上,然后再看32h,34h,36h,38h这些数字很奇怪,正好就是2、4、6、8的ASCII码,这让我们不禁想到了程序运行时屏幕上的那句话:

 UP----'8'   DOWN----'2'   LEFT----'4'     RIGHT----'6'

然后我们尝试手动发下信号,很容易便会发现,我们的猜想是正确的,这4个信号正好对应着4个方向。

然后接下来的事就可以很简单了,写个程序,将方向键换成发这4个信号,然后玩游戏就好,玩到30之后,就会获得flag的base64编码的值,解码即可。

最后玩游戏这步是队友做的,程序如下:

#include <stdio.h>
#include <termios.h>
#include <term.h>
#include <curses.h>
#include <unistd.h>
#include <sys/types.h>  
#include <stdlib.h>  
#include <signal.h> 

static struct termios initial_settings, new_settings;
static int peek_character = -1;
void init_keyboard();
void close_keyboard();
int kbhit();
int readch();

int main( int argc, char *argv[])
{
    int ch = 0;
    
    init_keyboard();
    pid_t pid;  
    pid = atoi(argv[1]);   //先运行snake,然后获得进程pid,作为参数传进来
    //printf(pid);
    while(ch != 'q') {		//w,a,s,d经典上下左右按键
        if(kbhit()) {
            ch = readch();
            switch (ch) {
            	case 'w':
            		kill(pid, 56); 
            		break; 
            	case 'a':
            		kill(pid, 52);  
            		break; 
            	case 's':
            		kill(pid, 50);  
            		break; 
            	case 'd':
            		kill(pid, 54); 
            		break; 
            }
        }
    } 
    close_keyboard();
    exit(0);
}

void init_keyboard()
{
    tcgetattr(0,&initial_settings);
    new_settings = initial_settings;
    new_settings.c_lflag &= ~ICANON;
    new_settings.c_lflag &= ~ECHO;
    new_settings.c_lflag &= ~ISIG;
    new_settings.c_cc[VMIN] = 1;
    new_settings.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &new_settings);
}

void close_keyboard()
{
    tcsetattr(0, TCSANOW, &initial_settings);
}

int kbhit()
{
    char ch;
    int nread;
    if(peek_character != -1)
        return 1;
    new_settings.c_cc[VMIN]=0;
    tcsetattr(0, TCSANOW, &new_settings);
    nread = read(0,&ch,1);
    new_settings.c_cc[VMIN]=1;
    tcsetattr(0, TCSANOW, &new_settings);
	if(nread == 1) {
    	  peek_character = ch;
    	  return 1;
	}
	return 0;
}

int readch()
{
    char ch;
    if(peek_character != -1) {
        ch = peek_character;
        peek_character = -1;
        return ch;
    }
    read(0,&ch,1);
    return ch;
}

我最开始是为了方便,想写个shell的脚本来做的,结果在网上各种搜不到,搜到的唯一一个还用不起来,我也是醉了……最后实现的是一个需要每次输入之后回车的,然后就感觉蛇跑太快了,玩不过去,于是就先放着给队友了……

其实当时还想过打补丁、改内存神马的方式来弄的,不过在Linux也不太会弄,然后就放弃了……

最后比赛结束后才想起来,可以把命令行的窗口拉大,这样游戏范围就变大了,这样就算是每次输入后回车也毫无压力玩过了,瞬间感觉自己当时好脑残……

按说这道题是可以完全靠逆向做出来,不用玩游戏的,不过自己水平不济,连程序整体都没大看明白,就更别谈那个复杂的要死的给答案的部分了。

snake.zip

挂载网络文件夹后网络故障时文件操作命令卡死

挂载 NFS 或者 Samba 的时候,经常会由于网络故障导致挂载好的链接断掉。此时如果尝试进行 ls、cd、df 等各种命令,只要与此目录沾上边,就会卡住。如果使用了类似 oh-my-zsh 这种配置的,只要在网络目录中,弹出命令提示符前就会直接卡住。这个时候第一反应就是...… Continue reading

路由折腾记 第四弹

Published on September 02, 2017